// Copyright (c) 2015 The Khronos Group Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and/or associated documentation files (the
// "Materials"), to deal in the Materials without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Materials, and to
// permit persons to whom the Materials are furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Materials.
//
// THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
// MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.

import platform "platform.api"

///////////////
// Constants //
///////////////

// API version (major.minor.patch)
define VERSION_MAJOR 1
define VERSION_MINOR 0
define VERSION_PATCH 13

// API limits
define VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 256
define VK_UUID_SIZE                     16
define VK_MAX_EXTENSION_NAME_SIZE       256
define VK_MAX_DESCRIPTION_SIZE          256
define VK_MAX_MEMORY_TYPES              32
define VK_MAX_MEMORY_HEAPS              16    /// The maximum number of unique memory heaps, each of which supporting 1 or more memory types.

// API keywords
define VK_TRUE        1
define VK_FALSE       0

// API keyword, but needs special handling by some templates
define NULL_HANDLE 0

@extension("VK_KHR_surface") define VK_KHR_SURFACE_SPEC_VERSION                 25
@extension("VK_KHR_surface") define VK_KHR_SURFACE_EXTENSION_NAME               "VK_KHR_surface"

@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_SPEC_VERSION             68
@extension("VK_KHR_swapchain") define VK_KHR_SWAPCHAIN_EXTENSION_NAME           "VK_KHR_swapchain"

@extension("VK_KHR_display") define VK_KHR_DISPLAY_SPEC_VERSION                 21
@extension("VK_KHR_display") define VK_KHR_DISPLAY_EXTENSION_NAME               "VK_KHR_display"

@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_SPEC_VERSION     9
@extension("VK_KHR_display_swapchain") define VK_KHR_DISPLAY_SWAPCHAIN_EXTENSION_NAME   "VK_KHR_display_swapchain"

@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_SPEC_VERSION       6
@extension("VK_KHR_xlib_surface") define VK_KHR_XLIB_SURFACE_NAME               "VK_KHR_xlib_surface"

@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_SPEC_VERSION         6
@extension("VK_KHR_xcb_surface") define VK_KHR_XCB_SURFACE_NAME                 "VK_KHR_xcb_surface"

@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_SPEC_VERSION 5
@extension("VK_KHR_wayland_surface") define VK_KHR_WAYLAND_SURFACE_NAME         "VK_KHR_wayland_surface"

@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_SPEC_VERSION         4
@extension("VK_KHR_mir_surface") define VK_KHR_MIR_SURFACE_NAME                 "VK_KHR_mir_surface"

@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_SPEC_VERSION 6
@extension("VK_KHR_android_surface") define VK_KHR_ANDROID_SURFACE_NAME         "VK_KHR_android_surface"

@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_SPEC_VERSION     5
@extension("VK_KHR_win32_surface") define VK_KHR_WIN32_SURFACE_NAME             "VK_KHR_win32_surface"

@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_SPEC_VERSION     5
@extension("VK_ANDROID_native_buffer") define VK_ANDROID_NATIVE_BUFFER_NAME             "VK_ANDROID_native_buffer"

@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_SPEC_VERSION       2
@extension("VK_EXT_debug_report") define VK_EXT_DEBUG_REPORT_NAME               "VK_EXT_debug_report"

@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_SPEC_VERSION           1
@extension("VK_NV_glsl_shader") define VK_NV_GLSL_SHADER_NAME                   "VK_NV_glsl_shader"

@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_SPEC_VERSION   1
@extension("VK_KHR_sampler_mirror_clamp_to_edge") define VK_KHR_SAMPLER_MIRROR_CLAMP_TO_EDGE_NAME           "VK_KHR_sampler_mirror_clamp_to_edge"

@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_SPEC_VERSION       1
@extension("VK_IMG_filter_cubic") define VK_IMG_FILTER_CUBIC_NAME               "VK_IMG_filter_cubic"

@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_SPEC_VERSION   1
@extension("VK_AMD_rasterization_order") define VK_AMD_RASTERIZATION_ORDER_NAME           "VK_AMD_rasterization_order"

@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_SPEC_VERSION       3
@extension("VK_EXT_debug_marker") define VK_EXT_DEBUG_MARKER_NAME               "VK_EXT_debug_marker"


/////////////
//  Types  //
/////////////

type u32 VkBool32
type u32 VkFlags
type u64 VkDeviceSize
type u32 VkSampleMask

/// Dispatchable handle types.
@dispatchHandle type u64 VkInstance
@dispatchHandle type u64 VkPhysicalDevice
@dispatchHandle type u64 VkDevice
@dispatchHandle type u64 VkQueue
@dispatchHandle type u64 VkCommandBuffer

/// Non dispatchable handle types.
@nonDispatchHandle type u64 VkDeviceMemory
@nonDispatchHandle type u64 VkCommandPool
@nonDispatchHandle type u64 VkBuffer
@nonDispatchHandle type u64 VkBufferView
@nonDispatchHandle type u64 VkImage
@nonDispatchHandle type u64 VkImageView
@nonDispatchHandle type u64 VkShaderModule
@nonDispatchHandle type u64 VkPipeline
@nonDispatchHandle type u64 VkPipelineLayout
@nonDispatchHandle type u64 VkSampler
@nonDispatchHandle type u64 VkDescriptorSet
@nonDispatchHandle type u64 VkDescriptorSetLayout
@nonDispatchHandle type u64 VkDescriptorPool
@nonDispatchHandle type u64 VkFence
@nonDispatchHandle type u64 VkSemaphore
@nonDispatchHandle type u64 VkEvent
@nonDispatchHandle type u64 VkQueryPool
@nonDispatchHandle type u64 VkFramebuffer
@nonDispatchHandle type u64 VkRenderPass
@nonDispatchHandle type u64 VkPipelineCache

@extension("VK_KHR_surface")    @nonDispatchHandle type u64 VkSurfaceKHR

@extension("VK_KHR_swapchain")  @nonDispatchHandle type u64 VkSwapchainKHR

@extension("VK_KHR_display")    @nonDispatchHandle type u64 VkDisplayKHR
@extension("VK_KHR_display")    @nonDispatchHandle type u64 VkDisplayModeKHR

@extension("VK_EXT_debug_report") @nonDispatchHandle type u64 VkDebugReportCallbackEXT


/////////////
//  Enums  //
/////////////

enum VkImageLayout {
    VK_IMAGE_LAYOUT_UNDEFINED                               = 0x00000000,   /// Implicit layout an image is when its contents are undefined due to various reasons (e.g. right after creation)
    VK_IMAGE_LAYOUT_GENERAL                                 = 0x00000001,   /// General layout when image can be used for any kind of access
    VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL                = 0x00000002,   /// Optimal layout when image is only used for color attachment read/write
    VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL        = 0x00000003,   /// Optimal layout when image is only used for depth/stencil attachment read/write
    VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL         = 0x00000004,   /// Optimal layout when image is used for read only depth/stencil attachment and shader access
    VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL                = 0x00000005,   /// Optimal layout when image is used for read only shader access
    VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL                    = 0x00000006,   /// Optimal layout when image is used only as source of transfer operations
    VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL                    = 0x00000007,   /// Optimal layout when image is used only as destination of transfer operations
    VK_IMAGE_LAYOUT_PREINITIALIZED                          = 0x00000008,   /// Initial layout used when the data is populated by the CPU

    //@extension("VK_KHR_swapchain")
    VK_IMAGE_LAYOUT_PRESENT_SRC_KHR                         = 1000001002,
}

enum VkAttachmentLoadOp {
    VK_ATTACHMENT_LOAD_OP_LOAD                              = 0x00000000,
    VK_ATTACHMENT_LOAD_OP_CLEAR                             = 0x00000001,
    VK_ATTACHMENT_LOAD_OP_DONT_CARE                         = 0x00000002,
}

enum VkAttachmentStoreOp {
    VK_ATTACHMENT_STORE_OP_STORE                            = 0x00000000,
    VK_ATTACHMENT_STORE_OP_DONT_CARE                        = 0x00000001,
}

enum VkImageType {
    VK_IMAGE_TYPE_1D                                        = 0x00000000,
    VK_IMAGE_TYPE_2D                                        = 0x00000001,
    VK_IMAGE_TYPE_3D                                        = 0x00000002,
}

enum VkImageTiling {
    VK_IMAGE_TILING_OPTIMAL                                 = 0x00000000,
    VK_IMAGE_TILING_LINEAR                                  = 0x00000001,
}

enum VkImageViewType {
    VK_IMAGE_VIEW_TYPE_1D                                   = 0x00000000,
    VK_IMAGE_VIEW_TYPE_2D                                   = 0x00000001,
    VK_IMAGE_VIEW_TYPE_3D                                   = 0x00000002,
    VK_IMAGE_VIEW_TYPE_CUBE                                 = 0x00000003,
    VK_IMAGE_VIEW_TYPE_1D_ARRAY                             = 0x00000004,
    VK_IMAGE_VIEW_TYPE_2D_ARRAY                             = 0x00000005,
    VK_IMAGE_VIEW_TYPE_CUBE_ARRAY                           = 0x00000006,
}

enum VkCommandBufferLevel {
    VK_COMMAND_BUFFER_LEVEL_PRIMARY                         = 0x00000000,
    VK_COMMAND_BUFFER_LEVEL_SECONDARY                       = 0x00000001,
}

enum VkComponentSwizzle {
    VK_COMPONENT_SWIZZLE_IDENTITY                           = 0x00000000,
    VK_COMPONENT_SWIZZLE_ZERO                               = 0x00000001,
    VK_COMPONENT_SWIZZLE_ONE                                = 0x00000002,
    VK_COMPONENT_SWIZZLE_R                                  = 0x00000003,
    VK_COMPONENT_SWIZZLE_G                                  = 0x00000004,
    VK_COMPONENT_SWIZZLE_B                                  = 0x00000005,
    VK_COMPONENT_SWIZZLE_A                                  = 0x00000006,
}

enum VkDescriptorType {
    VK_DESCRIPTOR_TYPE_SAMPLER                              = 0x00000000,
    VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER               = 0x00000001,
    VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE                        = 0x00000002,
    VK_DESCRIPTOR_TYPE_STORAGE_IMAGE                        = 0x00000003,
    VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER                 = 0x00000004,
    VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER                 = 0x00000005,
    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER                       = 0x00000006,
    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER                       = 0x00000007,
    VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC               = 0x00000008,
    VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC               = 0x00000009,
    VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT                     = 0x0000000a,
}

enum VkQueryType {
    VK_QUERY_TYPE_OCCLUSION                                 = 0x00000000,
    VK_QUERY_TYPE_PIPELINE_STATISTICS                       = 0x00000001, /// Optional
    VK_QUERY_TYPE_TIMESTAMP                                 = 0x00000002,
}

enum VkBorderColor {
    VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK                 = 0x00000000,
    VK_BORDER_COLOR_INT_TRANSPARENT_BLACK                   = 0x00000001,
    VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK                      = 0x00000002,
    VK_BORDER_COLOR_INT_OPAQUE_BLACK                        = 0x00000003,
    VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE                      = 0x00000004,
    VK_BORDER_COLOR_INT_OPAQUE_WHITE                        = 0x00000005,
}

enum VkPipelineBindPoint {
    VK_PIPELINE_BIND_POINT_GRAPHICS                         = 0x00000000,
    VK_PIPELINE_BIND_POINT_COMPUTE                          = 0x00000001,
}

enum VkPrimitiveTopology {
    VK_PRIMITIVE_TOPOLOGY_POINT_LIST                        = 0x00000000,
    VK_PRIMITIVE_TOPOLOGY_LINE_LIST                         = 0x00000001,
    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP                        = 0x00000002,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST                     = 0x00000003,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP                    = 0x00000004,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN                      = 0x00000005,
    VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY          = 0x00000006,
    VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY         = 0x00000007,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY      = 0x00000008,
    VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY     = 0x00000009,
    VK_PRIMITIVE_TOPOLOGY_PATCH_LIST                        = 0x0000000a,
}

enum VkSharingMode {
    VK_SHARING_MODE_EXCLUSIVE                               = 0x00000000,
    VK_SHARING_MODE_CONCURRENT                              = 0x00000001,
}

enum VkIndexType {
    VK_INDEX_TYPE_UINT16                                    = 0x00000000,
    VK_INDEX_TYPE_UINT32                                    = 0x00000001,
}

enum VkFilter {
    VK_FILTER_NEAREST                                       = 0x00000000,
    VK_FILTER_LINEAR                                        = 0x00000001,

    //@extension("VK_IMG_filter_cubic")
    VK_FILTER_CUBIC_IMG                                     = 1000015000,
}

enum VkSamplerMipmapMode {
    VK_SAMPLER_MIPMAP_MODE_NEAREST                          = 0x00000001,   /// Choose nearest mip level
    VK_SAMPLER_MIPMAP_MODE_LINEAR                           = 0x00000002,   /// Linear filter between mip levels
}

enum VkSamplerAddressMode {
    VK_SAMPLER_ADDRESS_MODE_REPEAT                          = 0x00000000,
    VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT                 = 0x00000001,
    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE                   = 0x00000002,
    VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER                 = 0x00000003,
    VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE            = 0x00000004,
}

enum VkCompareOp {
    VK_COMPARE_OP_NEVER                                     = 0x00000000,
    VK_COMPARE_OP_LESS                                      = 0x00000001,
    VK_COMPARE_OP_EQUAL                                     = 0x00000002,
    VK_COMPARE_OP_LESS_OR_EQUAL                             = 0x00000003,
    VK_COMPARE_OP_GREATER                                   = 0x00000004,
    VK_COMPARE_OP_NOT_EQUAL                                 = 0x00000005,
    VK_COMPARE_OP_GREATER_OR_EQUAL                          = 0x00000006,
    VK_COMPARE_OP_ALWAYS                                    = 0x00000007,
}

enum VkPolygonMode {
    VK_POLYGON_MODE_FILL                                    = 0x00000000,
    VK_POLYGON_MODE_LINE                                    = 0x00000001,
    VK_POLYGON_MODE_POINT                                   = 0x00000002,
}

enum VkFrontFace {
    VK_FRONT_FACE_COUNTER_CLOCKWISE                         = 0x00000000,
    VK_FRONT_FACE_CLOCKWISE                                 = 0x00000001,
}

enum VkBlendFactor {
    VK_BLEND_FACTOR_ZERO                                    = 0x00000000,
    VK_BLEND_FACTOR_ONE                                     = 0x00000001,
    VK_BLEND_FACTOR_SRC_COLOR                               = 0x00000002,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR                     = 0x00000003,
    VK_BLEND_FACTOR_DST_COLOR                               = 0x00000004,
    VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR                     = 0x00000005,
    VK_BLEND_FACTOR_SRC_ALPHA                               = 0x00000006,
    VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA                     = 0x00000007,
    VK_BLEND_FACTOR_DST_ALPHA                               = 0x00000008,
    VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA                     = 0x00000009,
    VK_BLEND_FACTOR_CONSTANT_COLOR                          = 0x0000000a,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR                = 0x0000000b,
    VK_BLEND_FACTOR_CONSTANT_ALPHA                          = 0x0000000c,
    VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA                = 0x0000000d,
    VK_BLEND_FACTOR_SRC_ALPHA_SATURATE                      = 0x0000000e,
    VK_BLEND_FACTOR_SRC1_COLOR                              = 0x0000000f,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_COLOR                    = 0x00000010,
    VK_BLEND_FACTOR_SRC1_ALPHA                              = 0x00000011,
    VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA                    = 0x00000012,
}

enum VkBlendOp {
    VK_BLEND_OP_ADD                                         = 0x00000000,
    VK_BLEND_OP_SUBTRACT                                    = 0x00000001,
    VK_BLEND_OP_REVERSE_SUBTRACT                            = 0x00000002,
    VK_BLEND_OP_MIN                                         = 0x00000003,
    VK_BLEND_OP_MAX                                         = 0x00000004,
}

enum VkStencilOp {
    VK_STENCIL_OP_KEEP                                      = 0x00000000,
    VK_STENCIL_OP_ZERO                                      = 0x00000001,
    VK_STENCIL_OP_REPLACE                                   = 0x00000002,
    VK_STENCIL_OP_INCREMENT_AND_CLAMP                       = 0x00000003,
    VK_STENCIL_OP_DECREMENT_AND_CLAMP                       = 0x00000004,
    VK_STENCIL_OP_INVERT                                    = 0x00000005,
    VK_STENCIL_OP_INCREMENT_AND_WRAP                        = 0x00000006,
    VK_STENCIL_OP_DECREMENT_AND_WRAP                        = 0x00000007,
}

enum VkLogicOp {
    VK_LOGIC_OP_CLEAR                                       = 0x00000000,
    VK_LOGIC_OP_AND                                         = 0x00000001,
    VK_LOGIC_OP_AND_REVERSE                                 = 0x00000002,
    VK_LOGIC_OP_COPY                                        = 0x00000003,
    VK_LOGIC_OP_AND_INVERTED                                = 0x00000004,
    VK_LOGIC_OP_NO_OP                                       = 0x00000005,
    VK_LOGIC_OP_XOR                                         = 0x00000006,
    VK_LOGIC_OP_OR                                          = 0x00000007,
    VK_LOGIC_OP_NOR                                         = 0x00000008,
    VK_LOGIC_OP_EQUIVALENT                                  = 0x00000009,
    VK_LOGIC_OP_INVERT                                      = 0x0000000a,
    VK_LOGIC_OP_OR_REVERSE                                  = 0x0000000b,
    VK_LOGIC_OP_COPY_INVERTED                               = 0x0000000c,
    VK_LOGIC_OP_OR_INVERTED                                 = 0x0000000d,
    VK_LOGIC_OP_NAND                                        = 0x0000000e,
    VK_LOGIC_OP_SET                                         = 0x0000000f,
}

enum VkSystemAllocationScope {
    VK_SYSTEM_ALLOCATION_SCOPE_COMMAND                      = 0x00000000,
    VK_SYSTEM_ALLOCATION_SCOPE_OBJECT                       = 0x00000001,
    VK_SYSTEM_ALLOCATION_SCOPE_CACHE                        = 0x00000002,
    VK_SYSTEM_ALLOCATION_SCOPE_DEVICE                       = 0x00000003,
    VK_SYSTEM_ALLOCATION_SCOPE_INSTANCE                     = 0x00000004,
}

enum VkInternalAllocationType {
    VK_INTERNAL_ALLOCATION_TYPE_EXECUTABLE                  = 0x00000000,
}

enum VkPhysicalDeviceType {
    VK_PHYSICAL_DEVICE_TYPE_OTHER                           = 0x00000000,
    VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU                  = 0x00000001,
    VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU                    = 0x00000002,
    VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU                     = 0x00000003,
    VK_PHYSICAL_DEVICE_TYPE_CPU                             = 0x00000004,
}

enum VkVertexInputRate {
    VK_VERTEX_INPUT_RATE_VERTEX                             = 0x00000000,
    VK_VERTEX_INPUT_RATE_INSTANCE                           = 0x00000001,
}

/// Vulkan format definitions
enum VkFormat {
    VK_FORMAT_UNDEFINED                                     = 0,
    VK_FORMAT_R4G4_UNORM_PACK8                              = 1,
    VK_FORMAT_R4G4B4A4_UNORM_PACK16                         = 2,
    VK_FORMAT_B4G4R4A4_UNORM_PACK16                         = 3,
    VK_FORMAT_R5G6B5_UNORM_PACK16                           = 4,
    VK_FORMAT_B5G6R5_UNORM_PACK16                           = 5,
    VK_FORMAT_R5G5B5A1_UNORM_PACK16                         = 6,
    VK_FORMAT_B5G5R5A1_UNORM_PACK16                         = 7,
    VK_FORMAT_A1R5G5B5_UNORM_PACK16                         = 8,
    VK_FORMAT_R8_UNORM                                      = 9,
    VK_FORMAT_R8_SNORM                                      = 10,
    VK_FORMAT_R8_USCALED                                    = 11,
    VK_FORMAT_R8_SSCALED                                    = 12,
    VK_FORMAT_R8_UINT                                       = 13,
    VK_FORMAT_R8_SINT                                       = 14,
    VK_FORMAT_R8_SRGB                                       = 15,
    VK_FORMAT_R8G8_UNORM                                    = 16,
    VK_FORMAT_R8G8_SNORM                                    = 17,
    VK_FORMAT_R8G8_USCALED                                  = 18,
    VK_FORMAT_R8G8_SSCALED                                  = 19,
    VK_FORMAT_R8G8_UINT                                     = 20,
    VK_FORMAT_R8G8_SINT                                     = 21,
    VK_FORMAT_R8G8_SRGB                                     = 22,
    VK_FORMAT_R8G8B8_UNORM                                  = 23,
    VK_FORMAT_R8G8B8_SNORM                                  = 24,
    VK_FORMAT_R8G8B8_USCALED                                = 25,
    VK_FORMAT_R8G8B8_SSCALED                                = 26,
    VK_FORMAT_R8G8B8_UINT                                   = 27,
    VK_FORMAT_R8G8B8_SINT                                   = 28,
    VK_FORMAT_R8G8B8_SRGB                                   = 29,
    VK_FORMAT_B8G8R8_UNORM                                  = 30,
    VK_FORMAT_B8G8R8_SNORM                                  = 31,
    VK_FORMAT_B8G8R8_USCALED                                = 32,
    VK_FORMAT_B8G8R8_SSCALED                                = 33,
    VK_FORMAT_B8G8R8_UINT                                   = 34,
    VK_FORMAT_B8G8R8_SINT                                   = 35,
    VK_FORMAT_B8G8R8_SRGB                                   = 36,
    VK_FORMAT_R8G8B8A8_UNORM                                = 37,
    VK_FORMAT_R8G8B8A8_SNORM                                = 38,
    VK_FORMAT_R8G8B8A8_USCALED                              = 39,
    VK_FORMAT_R8G8B8A8_SSCALED                              = 40,
    VK_FORMAT_R8G8B8A8_UINT                                 = 41,
    VK_FORMAT_R8G8B8A8_SINT                                 = 42,
    VK_FORMAT_R8G8B8A8_SRGB                                 = 43,
    VK_FORMAT_B8G8R8A8_UNORM                                = 44,
    VK_FORMAT_B8G8R8A8_SNORM                                = 45,
    VK_FORMAT_B8G8R8A8_USCALED                              = 46,
    VK_FORMAT_B8G8R8A8_SSCALED                              = 47,
    VK_FORMAT_B8G8R8A8_UINT                                 = 48,
    VK_FORMAT_B8G8R8A8_SINT                                 = 49,
    VK_FORMAT_B8G8R8A8_SRGB                                 = 50,
    VK_FORMAT_A8B8G8R8_UNORM_PACK32                         = 51,
    VK_FORMAT_A8B8G8R8_SNORM_PACK32                         = 52,
    VK_FORMAT_A8B8G8R8_USCALED_PACK32                       = 53,
    VK_FORMAT_A8B8G8R8_SSCALED_PACK32                       = 54,
    VK_FORMAT_A8B8G8R8_UINT_PACK32                          = 55,
    VK_FORMAT_A8B8G8R8_SINT_PACK32                          = 56,
    VK_FORMAT_A8B8G8R8_SRGB_PACK32                          = 57,
    VK_FORMAT_A2R10G10B10_UNORM_PACK32                      = 58,
    VK_FORMAT_A2R10G10B10_SNORM_PACK32                      = 59,
    VK_FORMAT_A2R10G10B10_USCALED_PACK32                    = 60,
    VK_FORMAT_A2R10G10B10_SSCALED_PACK32                    = 61,
    VK_FORMAT_A2R10G10B10_UINT_PACK32                       = 62,
    VK_FORMAT_A2R10G10B10_SINT_PACK32                       = 63,
    VK_FORMAT_A2B10G10R10_UNORM_PACK32                      = 64,
    VK_FORMAT_A2B10G10R10_SNORM_PACK32                      = 65,
    VK_FORMAT_A2B10G10R10_USCALED_PACK32                    = 66,
    VK_FORMAT_A2B10G10R10_SSCALED_PACK32                    = 67,
    VK_FORMAT_A2B10G10R10_UINT_PACK32                       = 68,
    VK_FORMAT_A2B10G10R10_SINT_PACK32                       = 69,
    VK_FORMAT_R16_UNORM                                     = 70,
    VK_FORMAT_R16_SNORM                                     = 71,
    VK_FORMAT_R16_USCALED                                   = 72,
    VK_FORMAT_R16_SSCALED                                   = 73,
    VK_FORMAT_R16_UINT                                      = 74,
    VK_FORMAT_R16_SINT                                      = 75,
    VK_FORMAT_R16_SFLOAT                                    = 76,
    VK_FORMAT_R16G16_UNORM                                  = 77,
    VK_FORMAT_R16G16_SNORM                                  = 78,
    VK_FORMAT_R16G16_USCALED                                = 79,
    VK_FORMAT_R16G16_SSCALED                                = 80,
    VK_FORMAT_R16G16_UINT                                   = 81,
    VK_FORMAT_R16G16_SINT                                   = 82,
    VK_FORMAT_R16G16_SFLOAT                                 = 83,
    VK_FORMAT_R16G16B16_UNORM                               = 84,
    VK_FORMAT_R16G16B16_SNORM                               = 85,
    VK_FORMAT_R16G16B16_USCALED                             = 86,
    VK_FORMAT_R16G16B16_SSCALED                             = 87,
    VK_FORMAT_R16G16B16_UINT                                = 88,
    VK_FORMAT_R16G16B16_SINT                                = 89,
    VK_FORMAT_R16G16B16_SFLOAT                              = 90,
    VK_FORMAT_R16G16B16A16_UNORM                            = 91,
    VK_FORMAT_R16G16B16A16_SNORM                            = 92,
    VK_FORMAT_R16G16B16A16_USCALED                          = 93,
    VK_FORMAT_R16G16B16A16_SSCALED                          = 94,
    VK_FORMAT_R16G16B16A16_UINT                             = 95,
    VK_FORMAT_R16G16B16A16_SINT                             = 96,
    VK_FORMAT_R16G16B16A16_SFLOAT                           = 97,
    VK_FORMAT_R32_UINT                                      = 98,
    VK_FORMAT_R32_SINT                                      = 99,
    VK_FORMAT_R32_SFLOAT                                    = 100,
    VK_FORMAT_R32G32_UINT                                   = 101,
    VK_FORMAT_R32G32_SINT                                   = 102,
    VK_FORMAT_R32G32_SFLOAT                                 = 103,
    VK_FORMAT_R32G32B32_UINT                                = 104,
    VK_FORMAT_R32G32B32_SINT                                = 105,
    VK_FORMAT_R32G32B32_SFLOAT                              = 106,
    VK_FORMAT_R32G32B32A32_UINT                             = 107,
    VK_FORMAT_R32G32B32A32_SINT                             = 108,
    VK_FORMAT_R32G32B32A32_SFLOAT                           = 109,
    VK_FORMAT_R64_UINT                                      = 110,
    VK_FORMAT_R64_SINT                                      = 111,
    VK_FORMAT_R64_SFLOAT                                    = 112,
    VK_FORMAT_R64G64_UINT                                   = 113,
    VK_FORMAT_R64G64_SINT                                   = 114,
    VK_FORMAT_R64G64_SFLOAT                                 = 115,
    VK_FORMAT_R64G64B64_UINT                                = 116,
    VK_FORMAT_R64G64B64_SINT                                = 117,
    VK_FORMAT_R64G64B64_SFLOAT                              = 118,
    VK_FORMAT_R64G64B64A64_UINT                             = 119,
    VK_FORMAT_R64G64B64A64_SINT                             = 120,
    VK_FORMAT_R64G64B64A64_SFLOAT                           = 121,
    VK_FORMAT_B10G11R11_UFLOAT_PACK32                       = 122,
    VK_FORMAT_E5B9G9R9_UFLOAT_PACK32                        = 123,
    VK_FORMAT_D16_UNORM                                     = 124,
    VK_FORMAT_X8_D24_UNORM_PACK32                           = 125,
    VK_FORMAT_D32_SFLOAT                                    = 126,
    VK_FORMAT_S8_UINT                                       = 127,
    VK_FORMAT_D16_UNORM_S8_UINT                             = 128,
    VK_FORMAT_D24_UNORM_S8_UINT                             = 129,
    VK_FORMAT_D32_SFLOAT_S8_UINT                            = 130,
    VK_FORMAT_BC1_RGB_UNORM_BLOCK                           = 131,
    VK_FORMAT_BC1_RGB_SRGB_BLOCK                            = 132,
    VK_FORMAT_BC1_RGBA_UNORM_BLOCK                          = 133,
    VK_FORMAT_BC1_RGBA_SRGB_BLOCK                           = 134,
    VK_FORMAT_BC2_UNORM_BLOCK                               = 135,
    VK_FORMAT_BC2_SRGB_BLOCK                                = 136,
    VK_FORMAT_BC3_UNORM_BLOCK                               = 137,
    VK_FORMAT_BC3_SRGB_BLOCK                                = 138,
    VK_FORMAT_BC4_UNORM_BLOCK                               = 139,
    VK_FORMAT_BC4_SNORM_BLOCK                               = 140,
    VK_FORMAT_BC5_UNORM_BLOCK                               = 141,
    VK_FORMAT_BC5_SNORM_BLOCK                               = 142,
    VK_FORMAT_BC6H_UFLOAT_BLOCK                             = 143,
    VK_FORMAT_BC6H_SFLOAT_BLOCK                             = 144,
    VK_FORMAT_BC7_UNORM_BLOCK                               = 145,
    VK_FORMAT_BC7_SRGB_BLOCK                                = 146,
    VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK                       = 147,
    VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK                        = 148,
    VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK                     = 149,
    VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK                      = 150,
    VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK                     = 151,
    VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK                      = 152,
    VK_FORMAT_EAC_R11_UNORM_BLOCK                           = 153,
    VK_FORMAT_EAC_R11_SNORM_BLOCK                           = 154,
    VK_FORMAT_EAC_R11G11_UNORM_BLOCK                        = 155,
    VK_FORMAT_EAC_R11G11_SNORM_BLOCK                        = 156,
    VK_FORMAT_ASTC_4x4_UNORM_BLOCK                          = 157,
    VK_FORMAT_ASTC_4x4_SRGB_BLOCK                           = 158,
    VK_FORMAT_ASTC_5x4_UNORM_BLOCK                          = 159,
    VK_FORMAT_ASTC_5x4_SRGB_BLOCK                           = 160,
    VK_FORMAT_ASTC_5x5_UNORM_BLOCK                          = 161,
    VK_FORMAT_ASTC_5x5_SRGB_BLOCK                           = 162,
    VK_FORMAT_ASTC_6x5_UNORM_BLOCK                          = 163,
    VK_FORMAT_ASTC_6x5_SRGB_BLOCK                           = 164,
    VK_FORMAT_ASTC_6x6_UNORM_BLOCK                          = 165,
    VK_FORMAT_ASTC_6x6_SRGB_BLOCK                           = 166,
    VK_FORMAT_ASTC_8x5_UNORM_BLOCK                          = 167,
    VK_FORMAT_ASTC_8x5_SRGB_BLOCK                           = 168,
    VK_FORMAT_ASTC_8x6_UNORM_BLOCK                          = 169,
    VK_FORMAT_ASTC_8x6_SRGB_BLOCK                           = 170,
    VK_FORMAT_ASTC_8x8_UNORM_BLOCK                          = 171,
    VK_FORMAT_ASTC_8x8_SRGB_BLOCK                           = 172,
    VK_FORMAT_ASTC_10x5_UNORM_BLOCK                         = 173,
    VK_FORMAT_ASTC_10x5_SRGB_BLOCK                          = 174,
    VK_FORMAT_ASTC_10x6_UNORM_BLOCK                         = 175,
    VK_FORMAT_ASTC_10x6_SRGB_BLOCK                          = 176,
    VK_FORMAT_ASTC_10x8_UNORM_BLOCK                         = 177,
    VK_FORMAT_ASTC_10x8_SRGB_BLOCK                          = 178,
    VK_FORMAT_ASTC_10x10_UNORM_BLOCK                        = 179,
    VK_FORMAT_ASTC_10x10_SRGB_BLOCK                         = 180,
    VK_FORMAT_ASTC_12x10_UNORM_BLOCK                        = 181,
    VK_FORMAT_ASTC_12x10_SRGB_BLOCK                         = 182,
    VK_FORMAT_ASTC_12x12_UNORM_BLOCK                        = 183,
    VK_FORMAT_ASTC_12x12_SRGB_BLOCK                         = 184,
}

/// Structure type enumerant
enum VkStructureType {
    VK_STRUCTURE_TYPE_APPLICATION_INFO                          = 0,
    VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO                      = 1,
    VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO                  = 2,
    VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO                        = 3,
    VK_STRUCTURE_TYPE_SUBMIT_INFO                               = 4,
    VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO                      = 5,
    VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE                       = 6,
    VK_STRUCTURE_TYPE_BIND_SPARSE_INFO                          = 7,
    VK_STRUCTURE_TYPE_FENCE_CREATE_INFO                         = 8,
    VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO                     = 9,
    VK_STRUCTURE_TYPE_EVENT_CREATE_INFO                         = 10,
    VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO                    = 11,
    VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO                        = 12,
    VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO                   = 13,
    VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO                         = 14,
    VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO                    = 15,
    VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO                 = 16,
    VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO                = 17,
    VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO         = 18,
    VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO   = 19,
    VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO = 20,
    VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO   = 21,
    VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO       = 22,
    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO  = 23,
    VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO    = 24,
    VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO  = 25,
    VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO    = 26,
    VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO        = 27,
    VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO             = 28,
    VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO              = 29,
    VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO               = 30,
    VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO                       = 31,
    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO         = 32,
    VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO               = 33,
    VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO              = 34,
    VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET                      = 35,
    VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET                       = 36,
    VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO                   = 37,
    VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO                   = 38,
    VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO                  = 39,
    VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO              = 40,
    VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO           = 41,
    VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO                 = 42,
    VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO                    = 43,
    VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER                     = 44,
    VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER                      = 45,
    VK_STRUCTURE_TYPE_MEMORY_BARRIER                            = 46,
    VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO               = 47,
    VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO                 = 48,

    //@extension("VK_KHR_swapchain")
    VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR                 = 1000001000,
    VK_STRUCTURE_TYPE_PRESENT_INFO_KHR                          = 1000001001,

    //@extension("VK_KHR_display")
    VK_STRUCTURE_TYPE_DISPLAY_MODE_CREATE_INFO_KHR              = 1000002000,
    VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR           = 1000002001,

    //@extension("VK_KHR_display_swapchain")
    VK_STRUCTURE_TYPE_DISPLAY_DISPLAY_PRESENT_INFO_KHR          = 1000003000,

    //@extension("VK_KHR_xlib_surface")
    VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR              = 1000004000,

    //@extension("VK_KHR_xcb_surface")
    VK_STRUCTURE_TYPE_XCB_SURFACE_CREATE_INFO_KHR               = 1000005000,

    //@extension("VK_KHR_wayland_surface")
    VK_STRUCTURE_TYPE_WAYLAND_SURFACE_CREATE_INFO_KHR           = 1000006000,

    //@extension("VK_KHR_mir_surface")
    VK_STRUCTURE_TYPE_MIR_SURFACE_CREATE_INFO_KHR               = 1000007000,

    //@extension("VK_KHR_android_surface")
    VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR           = 1000008000,

    //@extension("VK_KHR_win32_surface")
    VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR             = 1000009000,

    //@extension("VK_ANDROID_native_buffer")
    VK_STRUCTURE_TYPE_NATIVE_BUFFER_ANDROID                     = 1000010000,

    //@extension("VK_EXT_debug_report")
    VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT     = 1000011000,

    //@extension("VK_AMD_rasterization_order")
    VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_RASTERIZATION_ORDER_AMD = 1000018000,

    //@extension("VK_EXT_debug_marker")
    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_NAME_INFO_EXT         = 1000022000,

    //@extension("VK_EXT_debug_marker")
    VK_STRUCTURE_TYPE_DEBUG_MARKER_OBJECT_TAG_INFO_EXT          = 1000022001,

    //@extension("VK_EXT_debug_marker")
    VK_STRUCTURE_TYPE_DEBUG_MARKER_MARKER_INFO_EXT              = 1000022002,
}

enum VkSubpassContents {
    VK_SUBPASS_CONTENTS_INLINE                              = 0x00000000,
    VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS           = 0x00000001,
}

enum VkPipelineCacheHeaderVersion {
    VK_PIPELINE_CACHE_HEADER_VERSION_ONE                    = 1,
}

@lastUnused(-11)
/// Error and return codes
enum VkResult {
    // Return codes for successful operation execution (positive values)
    VK_SUCCESS                                              = 0,
    VK_NOT_READY                                            = 1,
    VK_TIMEOUT                                              = 2,
    VK_EVENT_SET                                            = 3,
    VK_EVENT_RESET                                          = 4,
    VK_INCOMPLETE                                           = 5,

    //@extension("VK_KHR_swapchain")
    VK_SUBOPTIMAL_KHR                                       = 1000001003,

    // Error codes (negative values)
    VK_ERROR_OUT_OF_HOST_MEMORY                             = 0xFFFFFFFF, // -1
    VK_ERROR_OUT_OF_DEVICE_MEMORY                           = 0xFFFFFFFE, // -2
    VK_ERROR_INITIALIZATION_FAILED                          = 0xFFFFFFFD, // -3
    VK_ERROR_DEVICE_LOST                                    = 0xFFFFFFFC, // -4
    VK_ERROR_MEMORY_MAP_FAILED                              = 0xFFFFFFFB, // -5
    VK_ERROR_LAYER_NOT_PRESENT                              = 0xFFFFFFFA, // -6
    VK_ERROR_EXTENSION_NOT_PRESENT                          = 0xFFFFFFF9, // -7
    VK_ERROR_FEATURE_NOT_PRESENT                            = 0xFFFFFFF8, // -8
    VK_ERROR_INCOMPATIBLE_DRIVER                            = 0xFFFFFFF7, // -9
    VK_ERROR_TOO_MANY_OBJECTS                               = 0xFFFFFFF6, // -10
    VK_ERROR_FORMAT_NOT_SUPPORTED                           = 0xFFFFFFF5, // -11

    //@extension("VK_KHR_surface")
    VK_ERROR_SURFACE_LOST_KHR                               = 0xC4653600, // -1000000000

    //@extension("VK_KHR_surface")
    VK_ERROR_NATIVE_WINDOW_IN_USE_KHR                       = 0xC46535FF, // -1000008001

    //@extension("VK_KHR_swapchain")
    VK_ERROR_OUT_OF_DATE_KHR                                = 0xC4653214, // -1000001004

    //@extension("VK_KHR_display_swapchain")
    VK_ERROR_INCOMPATIBLE_DISPLAY_KHR                       = 0xC4652A47, // -1000003001

    //@extension("VK_EXT_debug_report")
    VK_ERROR_VALIDATION_FAILED_EXT                          = 0xC4650B07, // -1000011001

    //@extension("VK_NV_glsl_shader")
    VK_ERROR_INVALID_SHADER_NV                              = 0xC4650720, // -1000012000
}

enum VkDynamicState {
    VK_DYNAMIC_STATE_VIEWPORT                               = 0x00000000,
    VK_DYNAMIC_STATE_SCISSOR                                = 0x00000001,
    VK_DYNAMIC_STATE_LINE_WIDTH                             = 0x00000002,
    VK_DYNAMIC_STATE_DEPTH_BIAS                             = 0x00000003,
    VK_DYNAMIC_STATE_BLEND_CONSTANTS                        = 0x00000004,
    VK_DYNAMIC_STATE_DEPTH_BOUNDS                           = 0x00000005,
    VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK                   = 0x00000006,
    VK_DYNAMIC_STATE_STENCIL_WRITE_MASK                     = 0x00000007,
    VK_DYNAMIC_STATE_STENCIL_REFERENCE                      = 0x00000008,
}

@extension("VK_KHR_surface")
enum VkPresentModeKHR {
    VK_PRESENT_MODE_IMMEDIATE_KHR                           = 0x00000000,
    VK_PRESENT_MODE_MAILBOX_KHR                             = 0x00000001,
    VK_PRESENT_MODE_FIFO_KHR                                = 0x00000002,
    VK_PRESENT_MODE_FIFO_RELAXED_KHR                        = 0x00000003,
}

@extension("VK_KHR_surface")
enum VkColorSpaceKHR {
    VK_COLORSPACE_SRGB_NONLINEAR_KHR                        = 0x00000000,
}

@extension("VK_EXT_debug_report")
enum VkDebugReportObjectTypeEXT {
    VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT                 = 0,
    VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT                = 1,
    VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT         = 2,
    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT                  = 3,
    VK_DEBUG_REPORT_OBJECT_TYPE_QUEUE_EXT                   = 4,
    VK_DEBUG_REPORT_OBJECT_TYPE_SEMAPHORE_EXT               = 5,
    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT          = 6,
    VK_DEBUG_REPORT_OBJECT_TYPE_FENCE_EXT                   = 7,
    VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_MEMORY_EXT           = 8,
    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT                  = 9,
    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT                   = 10,
    VK_DEBUG_REPORT_OBJECT_TYPE_EVENT_EXT                   = 11,
    VK_DEBUG_REPORT_OBJECT_TYPE_QUERY_POOL_EXT              = 12,
    VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_VIEW_EXT             = 13,
    VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_VIEW_EXT              = 14,
    VK_DEBUG_REPORT_OBJECT_TYPE_SHADER_MODULE_EXT           = 15,
    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_CACHE_EXT          = 16,
    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_LAYOUT_EXT         = 17,
    VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT             = 18,
    VK_DEBUG_REPORT_OBJECT_TYPE_PIPELINE_EXT                = 19,
    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT_EXT   = 20,
    VK_DEBUG_REPORT_OBJECT_TYPE_SAMPLER_EXT                 = 21,
    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_POOL_EXT         = 22,
    VK_DEBUG_REPORT_OBJECT_TYPE_DESCRIPTOR_SET_EXT          = 23,
    VK_DEBUG_REPORT_OBJECT_TYPE_FRAMEBUFFER_EXT             = 24,
    VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_POOL_EXT            = 25,
    VK_DEBUG_REPORT_OBJECT_TYPE_SURFACE_KHR_EXT             = 26,
    VK_DEBUG_REPORT_OBJECT_TYPE_SWAPCHAIN_KHR_EXT           = 27,
    VK_DEBUG_REPORT_OBJECT_TYPE_DEBUG_REPORT_EXT            = 28,
}

@extension("VK_EXT_debug_report")
enum VkDebugReportErrorEXT {
    VK_DEBUG_REPORT_ERROR_NONE_EXT                          = 0,
    VK_DEBUG_REPORT_ERROR_CALLBACK_REF_EXT                  = 1,
}

@extension("VK_AMD_rasterization_order")
enum VkRasterizationOrderAMD {
    VK_RASTERIZATION_ORDER_STRICT_AMD                       = 0,
    VK_RASTERIZATION_ORDER_RELAXED_AMD                      = 1,
}


/////////////////
//  Bitfields  //
/////////////////

/// Queue capabilities
type VkFlags VkQueueFlags
bitfield VkQueueFlagBits {
    VK_QUEUE_GRAPHICS_BIT                                   = 0x00000001,    /// Queue supports graphics operations
    VK_QUEUE_COMPUTE_BIT                                    = 0x00000002,    /// Queue supports compute operations
    VK_QUEUE_TRANSFER_BIT                                   = 0x00000004,    /// Queue supports transfer operations
    VK_QUEUE_SPARSE_BINDING_BIT                             = 0x00000008,    /// Queue supports sparse resource memory management operations
}

/// Memory properties passed into vkAllocMemory().
type VkFlags VkMemoryPropertyFlags
bitfield VkMemoryPropertyFlagBits {
    VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT                     = 0x00000001,
    VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT                     = 0x00000002,
    VK_MEMORY_PROPERTY_HOST_COHERENT_BIT                    = 0x00000004,
    VK_MEMORY_PROPERTY_HOST_CACHED_BIT                      = 0x00000008,
    VK_MEMORY_PROPERTY_LAZILY_ALLOCATED_BIT                 = 0x00000010,
}

/// Memory heap flags
type VkFlags VkMemoryHeapFlags
bitfield VkMemoryHeapFlagBits {
    VK_MEMORY_HEAP_DEVICE_LOCAL_BIT                         = 0x00000001,
}

/// Access flags
type VkFlags VkAccessFlags
bitfield VkAccessFlagBits {
    VK_ACCESS_INDIRECT_COMMAND_READ_BIT                     = 0x00000001,
    VK_ACCESS_INDEX_READ_BIT                                = 0x00000002,
    VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT                     = 0x00000004,
    VK_ACCESS_UNIFORM_READ_BIT                              = 0x00000008,
    VK_ACCESS_INPUT_ATTACHMENT_READ_BIT                     = 0x00000010,
    VK_ACCESS_SHADER_READ_BIT                               = 0x00000020,
    VK_ACCESS_SHADER_WRITE_BIT                              = 0x00000040,
    VK_ACCESS_COLOR_ATTACHMENT_READ_BIT                     = 0x00000080,
    VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT                    = 0x00000100,
    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT             = 0x00000200,
    VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT            = 0x00000400,
    VK_ACCESS_TRANSFER_READ_BIT                             = 0x00000800,
    VK_ACCESS_TRANSFER_WRITE_BIT                            = 0x00001000,
    VK_ACCESS_HOST_READ_BIT                                 = 0x00002000,
    VK_ACCESS_HOST_WRITE_BIT                                = 0x00004000,
    VK_ACCESS_MEMORY_READ_BIT                               = 0x00008000,
    VK_ACCESS_MEMORY_WRITE_BIT                              = 0x00010000,
}

/// Buffer usage flags
type VkFlags VkBufferUsageFlags
bitfield VkBufferUsageFlagBits {
    VK_BUFFER_USAGE_TRANSFER_SRC_BIT                        = 0x00000001,    /// Can be used as a source of transfer operations
    VK_BUFFER_USAGE_TRANSFER_DST_BIT                        = 0x00000002,    /// Can be used as a destination of transfer operations
    VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT                = 0x00000004,    /// Can be used as TBO
    VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT                = 0x00000008,    /// Can be used as IBO
    VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT                      = 0x00000010,    /// Can be used as UBO
    VK_BUFFER_USAGE_STORAGE_BUFFER_BIT                      = 0x00000020,    /// Can be used as SSBO
    VK_BUFFER_USAGE_INDEX_BUFFER_BIT                        = 0x00000040,    /// Can be used as source of fixed function index fetch (index buffer)
    VK_BUFFER_USAGE_VERTEX_BUFFER_BIT                       = 0x00000080,    /// Can be used as source of fixed function vertex fetch (VBO)
    VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT                     = 0x00000100,    /// Can be the source of indirect parameters (e.g. indirect buffer, parameter buffer)
}

/// Buffer creation flags
type VkFlags VkBufferCreateFlags
bitfield VkBufferCreateFlagBits {
    VK_BUFFER_CREATE_SPARSE_BINDING_BIT                     = 0x00000001,    /// Buffer should support sparse backing
    VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT                   = 0x00000002,    /// Buffer should support sparse backing with partial residency
    VK_BUFFER_CREATE_SPARSE_ALIASED_BIT                     = 0x00000004,    /// Buffer should support constent data access to physical memory blocks mapped into multiple locations of sparse buffers
}

/// Shader stage flags
type VkFlags VkShaderStageFlags
bitfield VkShaderStageFlagBits {
    VK_SHADER_STAGE_VERTEX_BIT                              = 0x00000001,
    VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT                = 0x00000002,
    VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT             = 0x00000004,
    VK_SHADER_STAGE_GEOMETRY_BIT                            = 0x00000008,
    VK_SHADER_STAGE_FRAGMENT_BIT                            = 0x00000010,
    VK_SHADER_STAGE_COMPUTE_BIT                             = 0x00000020,
    VK_SHADER_STAGE_ALL_GRAPHICS                            = 0x0000001F,

    VK_SHADER_STAGE_ALL                                     = 0x7FFFFFFF,
}

/// Descriptor pool create flags
type VkFlags VkDescriptorPoolCreateFlags
bitfield VkDescriptorPoolCreateFlagBits {
    VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT       = 0x00000001,
}

/// Descriptor pool reset flags
type VkFlags VkDescriptorPoolResetFlags
//bitfield VkDescriptorPoolResetFlagBits {
//}

/// Image usage flags
type VkFlags VkImageUsageFlags
bitfield VkImageUsageFlagBits {
    VK_IMAGE_USAGE_TRANSFER_SRC_BIT                         = 0x00000001,    /// Can be used as a source of transfer operations
    VK_IMAGE_USAGE_TRANSFER_DST_BIT                         = 0x00000002,    /// Can be used as a destination of transfer operations
    VK_IMAGE_USAGE_SAMPLED_BIT                              = 0x00000004,    /// Can be sampled from (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)
    VK_IMAGE_USAGE_STORAGE_BIT                              = 0x00000008,    /// Can be used as storage image (STORAGE_IMAGE descriptor type)
    VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT                     = 0x00000010,    /// Can be used as framebuffer color attachment
    VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT             = 0x00000020,    /// Can be used as framebuffer depth/stencil attachment
    VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT                 = 0x00000040,    /// Image data not needed outside of rendering
    VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT                     = 0x00000080,    /// Can be used as framebuffer input attachment
}

/// Image creation flags
type VkFlags VkImageCreateFlags
bitfield VkImageCreateFlagBits {
    VK_IMAGE_CREATE_SPARSE_BINDING_BIT                      = 0x00000001,    /// Image should support sparse backing
    VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT                    = 0x00000002,    /// Image should support sparse backing with partial residency
    VK_IMAGE_CREATE_SPARSE_ALIASED_BIT                      = 0x00000004,    /// Image should support constent data access to physical memory blocks mapped into multiple locations of sparse images
    VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT                      = 0x00000008,    /// Allows image views to have different format than the base image
    VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT                     = 0x00000010,    /// Allows creating image views with cube type from the created image
}

/// Image view creation flags
type VkFlags VkImageViewCreateFlags
//bitfield VkImageViewCreateFlagBits {
//}

/// Pipeline creation flags
type VkFlags VkPipelineCreateFlags
bitfield VkPipelineCreateFlagBits {
    VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT             = 0x00000001,
    VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT                = 0x00000002,
    VK_PIPELINE_CREATE_DERIVATIVE_BIT                       = 0x00000004,
}

/// Color component flags
type VkFlags VkColorComponentFlags
bitfield VkColorComponentFlagBits {
    VK_COLOR_COMPONENT_R_BIT                                = 0x00000001,
    VK_COLOR_COMPONENT_G_BIT                                = 0x00000002,
    VK_COLOR_COMPONENT_B_BIT                                = 0x00000004,
    VK_COLOR_COMPONENT_A_BIT                                = 0x00000008,
}

/// Fence creation flags
type VkFlags VkFenceCreateFlags
bitfield VkFenceCreateFlagBits {
    VK_FENCE_CREATE_SIGNALED_BIT                            = 0x00000001,
}

/// Semaphore creation flags
type VkFlags VkSemaphoreCreateFlags
//bitfield VkSemaphoreCreateFlagBits {
//}

/// Format capability flags
type VkFlags VkFormatFeatureFlags
bitfield VkFormatFeatureFlagBits {
    VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT                     = 0x00000001,    /// Format can be used for sampled images (SAMPLED_IMAGE and COMBINED_IMAGE_SAMPLER descriptor types)
    VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT                     = 0x00000002,    /// Format can be used for storage images (STORAGE_IMAGE descriptor type)
    VK_FORMAT_FEATURE_STORAGE_IMAGE_ATOMIC_BIT              = 0x00000004,    /// Format supports atomic operations in case it's used for storage images
    VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT              = 0x00000008,    /// Format can be used for uniform texel buffers (TBOs)
    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT              = 0x00000010,    /// Format can be used for storage texel buffers (IBOs)
    VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_ATOMIC_BIT       = 0x00000020,    /// Format supports atomic operations in case it's used for storage texel buffers
    VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT                     = 0x00000040,    /// Format can be used for vertex buffers (VBOs)
    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT                  = 0x00000080,    /// Format can be used for color attachment images
    VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT            = 0x00000100,    /// Format supports blending in case it's used for color attachment images
    VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT          = 0x00000200,    /// Format can be used for depth/stencil attachment images
    VK_FORMAT_FEATURE_BLIT_SRC_BIT                          = 0x00000400,    /// Format can be used as the source image of blits with vkCommandBlitImage
    VK_FORMAT_FEATURE_BLIT_DST_BIT                          = 0x00000800,    /// Format can be used as the destination image of blits with vkCommandBlitImage
    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT       = 0x00001000,

    //@extension("VK_IMG_filter_cubic")
    VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG    = 0x00002000,
}

/// Query control flags
type VkFlags VkQueryControlFlags
bitfield VkQueryControlFlagBits {
    VK_QUERY_CONTROL_PRECISE_BIT                            = 0x00000001,
}

/// Query result flags
type VkFlags VkQueryResultFlags
bitfield VkQueryResultFlagBits {
    VK_QUERY_RESULT_64_BIT                                  = 0x00000001,   /// Results of the queries are written to the destination buffer as 64-bit values
    VK_QUERY_RESULT_WAIT_BIT                                = 0x00000002,   /// Results of the queries are waited on before proceeding with the result copy
    VK_QUERY_RESULT_WITH_AVAILABILITY_BIT                   = 0x00000004,   /// Besides the results of the query, the availability of the results is also written
    VK_QUERY_RESULT_PARTIAL_BIT                             = 0x00000008,   /// Copy the partial results of the query even if the final results aren't available
}

/// Shader module creation flags
type VkFlags VkShaderModuleCreateFlags
//bitfield VkShaderModuleCreateFlagBits {
//}

/// Event creation flags
type VkFlags VkEventCreateFlags
//bitfield VkEventCreateFlagBits {
//}

/// Command buffer usage flags
type VkFlags VkCommandBufferUsageFlags
bitfield VkCommandBufferUsageFlagBits {
    VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT             = 0x00000001,
    VK_COMMAND_BUFFER_USAGE_RENDER_PASS_CONTINUE_BIT        = 0x00000002,
    VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT            = 0x00000004,
}

/// Pipeline statistics flags
type VkFlags VkQueryPipelineStatisticFlags
bitfield VkQueryPipelineStatisticFlagBits {
    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_VERTICES_BIT                     = 0x00000001,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_INPUT_ASSEMBLY_PRIMITIVES_BIT                   = 0x00000002,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_VERTEX_SHADER_INVOCATIONS_BIT                   = 0x00000004,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_INVOCATIONS_BIT                 = 0x00000008,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_GEOMETRY_SHADER_PRIMITIVES_BIT                  = 0x00000010,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_INVOCATIONS_BIT                        = 0x00000020,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_CLIPPING_PRIMITIVES_BIT                         = 0x00000040,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_FRAGMENT_SHADER_INVOCATIONS_BIT                 = 0x00000080,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_CONTROL_SHADER_PATCHES_BIT         = 0x00000100,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_TESSELLATION_EVALUATION_SHADER_INVOCATIONS_BIT  = 0x00000200,  /// Optional
    VK_QUERY_PIPELINE_STATISTIC_COMPUTE_SHADER_INVOCATIONS_BIT                  = 0x00000400,  /// Optional
}

/// Memory mapping flags
type VkFlags VkMemoryMapFlags
//bitfield VkMemoryMapFlagBits {
//}

/// Bitfield of image aspects
type VkFlags VkImageAspectFlags
bitfield VkImageAspectFlagBits {
    VK_IMAGE_ASPECT_COLOR_BIT                               = 0x00000001,
    VK_IMAGE_ASPECT_DEPTH_BIT                               = 0x00000002,
    VK_IMAGE_ASPECT_STENCIL_BIT                             = 0x00000004,
    VK_IMAGE_ASPECT_METADATA_BIT                            = 0x00000008,
}

/// Sparse memory bind flags
type VkFlags VkSparseMemoryBindFlags
bitfield VkSparseMemoryBindFlagBits {
    VK_SPARSE_MEMORY_BIND_METADATA_BIT                      = 0x00000001,
}

/// Sparse image memory requirements flags
type VkFlags VkSparseImageFormatFlags
bitfield VkSparseImageFormatFlagBits {
    VK_SPARSE_IMAGE_FORMAT_SINGLE_MIPTAIL_BIT                  = 0x00000001,  /// Image uses a single miptail region for all array slices
    VK_SPARSE_IMAGE_FORMAT_ALIGNED_MIP_SIZE_BIT                = 0x00000002,  /// Image requires mip levels to be an exact multiple of the sparse iamge block size for non-mip-tail levels.
    VK_SPARSE_IMAGE_FORMAT_NONSTANDARD_BLOCK_SIZE_BIT          = 0x00000004,  /// Image uses a non-standard sparse block size
}

/// Pipeline stages
type VkFlags VkPipelineStageFlags
bitfield VkPipelineStageFlagBits {
    VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT                       = 0x00000001,  /// Before subsequent commands are processed
    VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT                     = 0x00000002,  /// Draw/DispatchIndirect command fetch
    VK_PIPELINE_STAGE_VERTEX_INPUT_BIT                      = 0x00000004,  /// Vertex/index fetch
    VK_PIPELINE_STAGE_VERTEX_SHADER_BIT                     = 0x00000008,  /// Vertex shading
    VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT       = 0x00000010,  /// Tessellation control shading
    VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT    = 0x00000020,  /// Tessellation evaluation shading
    VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT                   = 0x00000040,  /// Geometry shading
    VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT                   = 0x00000080,  /// Fragment shading
    VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT              = 0x00000100,  /// Early fragment (depth/stencil) tests
    VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT               = 0x00000200,  /// Late fragment (depth/stencil) tests
    VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT           = 0x00000400,  /// Color attachment writes
    VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT                    = 0x00000800,  /// Compute shading
    VK_PIPELINE_STAGE_TRANSFER_BIT                          = 0x00001000,  /// Transfer/copy operations
    VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT                    = 0x00002000,
    VK_PIPELINE_STAGE_HOST_BIT                              = 0x00004000,  /// Indicates host (CPU) is a source/sink of the dependency

    VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT                      = 0x00008000,  /// All stages of the graphics pipeline
    VK_PIPELINE_STAGE_ALL_COMMANDS_BIT                      = 0x00010000,  /// All graphics, compute, copy, and transition commands
}

/// Render pass attachment description flags
type VkFlags VkAttachmentDescriptionFlags
bitfield VkAttachmentDescriptionFlagBits {
    VK_ATTACHMENT_DESCRIPTION_MAY_ALIAS_BIT                 = 0x00000001,  /// The attachment may alias physical memory of another attachment in the same renderpass
}

/// Subpass description flags
type VkFlags VkSubpassDescriptionFlags
bitfield VkSubpassDescriptionFlagBits {
}

/// Command pool creation flags
type VkFlags VkCommandPoolCreateFlags
bitfield VkCommandPoolCreateFlagBits {
    VK_COMMAND_POOL_CREATE_TRANSIENT_BIT                    = 0x00000001,  /// Command buffers have a short lifetime
    VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT         = 0x00000002,  /// Command buffers may release their memory individually
}

/// Command pool reset flags
type VkFlags VkCommandPoolResetFlags
bitfield VkCommandPoolResetFlagBits {
    VK_COMMAND_POOL_RESET_RELEASE_RESOURCES_BIT             = 0x00000001,  /// Release resources owned by the pool
}

type VkFlags VkCommandBufferResetFlags
bitfield VkCommandBufferResetFlagBits {
    VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT           = 0x00000001,  /// Release resources owned by the buffer
}

type VkFlags VkSampleCountFlags
bitfield VkSampleCountFlagBits {
    VK_SAMPLE_COUNT_1_BIT                                   = 0x00000001,
    VK_SAMPLE_COUNT_2_BIT                                   = 0x00000002,
    VK_SAMPLE_COUNT_4_BIT                                   = 0x00000004,
    VK_SAMPLE_COUNT_8_BIT                                   = 0x00000008,
    VK_SAMPLE_COUNT_16_BIT                                  = 0x00000010,
    VK_SAMPLE_COUNT_32_BIT                                  = 0x00000020,
    VK_SAMPLE_COUNT_64_BIT                                  = 0x00000040,
}

type VkFlags VkStencilFaceFlags
bitfield VkStencilFaceFlagBits {
    VK_STENCIL_FACE_FRONT_BIT                               = 0x00000001,   /// Front face
    VK_STENCIL_FACE_BACK_BIT                                = 0x00000002,   /// Back face
    VK_STENCIL_FRONT_AND_BACK                               = 0x00000003,
}

/// Instance creation flags
type VkFlags VkInstanceCreateFlags
//bitfield VkInstanceCreateFlagBits {
//}

/// Device creation flags
type VkFlags VkDeviceCreateFlags
//bitfield VkDeviceCreateFlagBits {
//}

/// Device queue creation flags
type VkFlags VkDeviceQueueCreateFlags
//bitfield VkDeviceQueueCreateFlagBits {
//}

/// Query pool creation flags
type VkFlags VkQueryPoolCreateFlags
//bitfield VkQueryPoolCreateFlagBits {
//}

/// Buffer view creation flags
type VkFlags VkBufferViewCreateFlags
//bitfield VkBufferViewCreateFlagBits {
//}

/// Pipeline cache creation flags
type VkFlags VkPipelineCacheCreateFlags
//bitfield VkPipelineCacheCreateFlagBits {
//}

/// Pipeline shader stage creation flags
type VkFlags VkPipelineShaderStageCreateFlags
//bitfield VkPipelineShaderStageCreateFlagBits {
//}

/// Descriptor set layout creation flags
type VkFlags VkDescriptorSetLayoutCreateFlags
//bitfield VkDescriptorSetLayoutCreateFlagBits {
//}

/// Pipeline vertex input state creation flags
type VkFlags VkPipelineVertexInputStateCreateFlags
//bitfield VkPipelineVertexInputStateCreateFlagBits {
//}

/// Pipeline input assembly state creation flags
type VkFlags VkPipelineInputAssemblyStateCreateFlags
//bitfield VkPipelineInputAssemblyStateCreateFlagBits {
//}

/// Tessellation state creation flags
type VkFlags VkPipelineTessellationStateCreateFlags
//bitfield VkPipelineTessellationStateCreateFlagBits {
//}

/// Viewport state creation flags
type VkFlags VkPipelineViewportStateCreateFlags
//bitfield VkPipelineViewportStateCreateFlagBits {
//}

/// Rasterization state creation flags
type VkFlags VkPipelineRasterizationStateCreateFlags
//bitfield VkPipelineRasterizationStateCreateFlagBits {
//}

/// Multisample state creation flags
type VkFlags VkPipelineMultisampleStateCreateFlags
//bitfield VkPipelineMultisampleStateCreateFlagBits {
//}

/// Color blend state creation flags
type VkFlags VkPipelineColorBlendStateCreateFlags
//bitfield VkPipelineColorBlendStateCreateFlagBits {
//}

/// Depth/stencil state creation flags
type VkFlags VkPipelineDepthStencilStateCreateFlags
//bitfield VkPipelineDepthStencilStateCreateFlagBits {
//}

/// Dynamic state creation flags
type VkFlags VkPipelineDynamicStateCreateFlags
//bitfield VkPipelineDynamicStateCreateFlagBits {
//}

/// Pipeline layout creation flags
type VkFlags VkPipelineLayoutCreateFlags
//bitfield VkPipelineLayoutCreateFlagBits {
//}

/// Sampler creation flags
type VkFlags VkSamplerCreateFlags
//bitfield VkSamplerCreateFlagBits {
//}

/// Render pass creation flags
type VkFlags VkRenderPassCreateFlags
//bitfield VkRenderPassCreateFlagBits {
//}

/// Framebuffer creation flags
type VkFlags VkFramebufferCreateFlags
//bitfield VkFramebufferCreateFlagBits {
//}

/// Dependency flags
type VkFlags VkDependencyFlags
bitfield VkDependencyFlagBits {
    VK_DEPENDENCY_BY_REGION_BIT                             = 0x00000001,
}

/// Cull mode flags
type VkFlags VkCullModeFlags
bitfield VkCullModeFlagBits {
    VK_CULL_MODE_NONE                                       = 0x00000000,
    VK_CULL_MODE_FRONT_BIT                                  = 0x00000001,
    VK_CULL_MODE_BACK_BIT                                   = 0x00000002,
    VK_CULL_MODE_FRONT_AND_BACK                             = 0x00000003,
}

@extension("VK_KHR_surface")
type VkFlags VkSurfaceTransformFlagsKHR
@extension("VK_KHR_surface")
bitfield VkSurfaceTransformFlagBitsKHR {
    VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR                       = 0x00000001,
    VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR                      = 0x00000002,
    VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR                     = 0x00000004,
    VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR                     = 0x00000008,
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR              = 0x00000010,
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_90_BIT_KHR    = 0x00000020,
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR   = 0x00000040,
    VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_270_BIT_KHR   = 0x00000080,
    VK_SURFACE_TRANSFORM_INHERIT_BIT_KHR                        = 0x00000100,
}

@extension("VK_KHR_surface")
type VkFlags VkCompositeAlphaFlagsKHR
@extension("VK_KHR_surface")
bitfield VkCompositeAlphaFlagBitsKHR {
    VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR                       = 0x00000001,
    VK_COMPOSITE_ALPHA_PRE_MULTIPLIED_BIT_KHR               = 0x00000002,
    VK_COMPOSITE_ALPHA_POST_MULTIPLIED_BIT_KHR              = 0x00000004,
    VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR                      = 0x00000008,
}

@extension("VK_KHR_swapchain")
type VkFlags VkSwapchainCreateFlagsKHR
//@extension("VK_KHR_swapchain")
//bitfield VkSwapchainCreateFlagBitsKHR {
//}

@extension("VK_KHR_display")
type VkFlags VkDisplayPlaneAlphaFlagsKHR
@extension("VK_KHR_display")
bitfield VkDisplayPlaneAlphaFlagBitsKHR {
    VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR                   = 0x00000001,
    VK_DISPLAY_PLANE_ALPHA_GLOBAL_BIT_KHR                   = 0x00000002,
    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_BIT_KHR                = 0x00000004,
    VK_DISPLAY_PLANE_ALPHA_PER_PIXEL_PREMULTIPLIED_BIT_KHR  = 0x00000008,
}

@extension("VK_KHR_display")
type VkFlags VkDisplaySurfaceCreateFlagsKHR
//@extension("VK_KHR_display")
//bitfield VkDisplaySurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_display")
type VkFlags VkDisplayModeCreateFlagsKHR
//@extension("VK_KHR_display")
//bitfield VkDisplayModeCreateFlagBitsKHR {
//}

@extension("VK_KHR_xlib_surface")
type VkFlags VkXlibSurfaceCreateFlagsKHR
//@extension("VK_KHR_xlib_surface")
//bitfield VkXlibSurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_xcb_surface")
type VkFlags VkXcbSurfaceCreateFlagsKHR
//@extension("VK_KHR_xcb_surface")
//bitfield VkXcbSurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_wayland_surface")
type VkFlags VkWaylandSurfaceCreateFlagsKHR
//@extension("VK_KHR_wayland_surface")
//bitfield VkWaylandSurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_mir_surface")
type VkFlags VkMirSurfaceCreateFlagsKHR
//@extension("VK_KHR_mir_surface")
//bitfield VkMirSurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_android_surface")
type VkFlags VkAndroidSurfaceCreateFlagsKHR
//@extension("VK_KHR_android_surface")
//bitfield VkAndroidSurfaceCreateFlagBitsKHR {
//}

@extension("VK_KHR_win32_surface")
type VkFlags VkWin32SurfaceCreateFlagsKHR
//@extension("VK_KHR_win32_surface")
//bitfield VkWin32SurfaceCreateFlagBitsKHR {
//}

@extension("VK_EXT_debug_report")
type VkFlags VkDebugReportFlagsEXT
@extension("VK_EXT_debug_report")
bitfield VkDebugReportFlagBitsEXT {
    VK_DEBUG_REPORT_INFORMATION_BIT_EXT                     = 0x00000001,
    VK_DEBUG_REPORT_WARNING_BIT_EXT                         = 0x00000002,
    VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT             = 0x00000004,
    VK_DEBUG_REPORT_ERROR_BIT_EXT                           = 0x00000008,
    VK_DEBUG_REPORT_DEBUG_BIT_EXT                           = 0x00000010,
}


//////////////////
//  Structures  //
//////////////////

class VkOffset2D {
    s32                                         x
    s32                                         y
}

class VkOffset3D {
    s32                                         x
    s32                                         y
    s32                                         z
}

class VkExtent2D {
    u32                                         width
    u32                                         height
}

class VkExtent3D {
    u32                                         width
    u32                                         height
    u32                                         depth
}

class VkViewport {
    f32                                         x
    f32                                         y
    f32                                         width
    f32                                         height
    f32                                         minDepth
    f32                                         maxDepth
}

class VkRect2D {
    VkOffset2D                                  offset
    VkExtent2D                                  extent
}

class VkClearRect {
    VkRect2D                                    rect
    u32                                         baseArrayLayer
    u32                                         layerCount
}

class VkComponentMapping {
    VkComponentSwizzle                          r
    VkComponentSwizzle                          g
    VkComponentSwizzle                          b
    VkComponentSwizzle                          a
}

class VkPhysicalDeviceProperties {
    u32                                         apiVersion
    u32                                         driverVersion
    u32                                         vendorID
    u32                                         deviceID
    VkPhysicalDeviceType                        deviceType
    char[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE]      deviceName
    u8[VK_UUID_SIZE]                            pipelineCacheUUID
    VkPhysicalDeviceLimits                      limits
    VkPhysicalDeviceSparseProperties            sparseProperties
}

class VkExtensionProperties {
    char[VK_MAX_EXTENSION_NAME_SIZE]            extensionName      /// extension name
    u32                                         specVersion        /// version of the extension specification implemented
}

class VkLayerProperties {
    char[VK_MAX_EXTENSION_NAME_SIZE]            layerName               /// layer name
    u32                                         specVersion             /// version of the layer specification implemented
    u32                                         implementationVersion   /// build or release version of the layer's library
    char[VK_MAX_DESCRIPTION_SIZE]               description             /// Free-form description of the layer
}

class VkSubmitInfo {
    VkStructureType                             sType              /// Type of structure. Should be VK_STRUCTURE_TYPE_SUBMIT_INFO
    const void*                                 pNext              /// Next structure in chain
    u32                                         waitSemaphoreCount
    const VkSemaphore*                          pWaitSemaphores
    const VkPipelineStageFlags*                 pWaitDstStageMask
    u32                                         commandBufferCount
    const VkCommandBuffer*                      pCommandBuffers
    u32                                         signalSemaphoreCount
    const VkSemaphore*                          pSignalSemaphores
}

class VkApplicationInfo {
    VkStructureType                             sType              /// Type of structure. Should be VK_STRUCTURE_TYPE_APPLICATION_INFO
    const void*                                 pNext              /// Next structure in chain
    const char*                                 pApplicationName
    u32                                         applicationVersion
    const char*                                 pEngineName
    u32                                         engineVersion
    u32                                         apiVersion
}

class VkAllocationCallbacks {
    void*                                       pUserData
    PFN_vkAllocationFunction                    pfnAllocation
    PFN_vkReallocationFunction                  pfnReallocation
    PFN_vkFreeFunction                          pfnFree
    PFN_vkInternalAllocationNotification        pfnInternalAllocation
    PFN_vkInternalFreeNotification              pfnInternalFree
}

class VkDeviceQueueCreateInfo {
    VkStructureType                             sStype                    /// Should be VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
    const void*                                 pNext                     /// Pointer to next structure
    VkDeviceQueueCreateFlags                    flags
    u32                                         queueFamilyIndex
    u32                                         queueCount
    const f32*                                  pQueuePriorities
}

class VkDeviceCreateInfo {
    VkStructureType                             sType                      /// Should be VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
    const void*                                 pNext                      /// Pointer to next structure
    VkDeviceCreateFlags                         flags
    u32                                         queueCreateInfoCount
    const VkDeviceQueueCreateInfo*              pQueueCreateInfos
    u32                                         enabledLayerCount
    const char* const*                          ppEnabledLayerNames        /// Ordered list of layer names to be enabled
    u32                                         enabledExtensionCount
    const char* const*                          ppEnabledExtensionNames
    const VkPhysicalDeviceFeatures*             pEnabledFeatures
}

class VkInstanceCreateInfo {
    VkStructureType                             sType                      /// Should be VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
    const void*                                 pNext                      /// Pointer to next structure
    VkInstanceCreateFlags                       flags
    const VkApplicationInfo*                    pApplicationInfo
    u32                                         enabledLayerCount
    const char* const*                          ppEnabledLayerNames        /// Ordered list of layer names to be enabled
    u32                                         enabledExtensionCount
    const char* const*                          ppEnabledExtensionNames    /// Extension names to be enabled
}

class VkQueueFamilyProperties {
    VkQueueFlags                                queueFlags                 /// Queue flags
    u32                                         queueCount
    u32                                         timestampValidBits
    VkExtent3D                                  minImageTransferGranularity
}

class VkPhysicalDeviceMemoryProperties {
    u32                                         memoryTypeCount
    VkMemoryType[VK_MAX_MEMORY_TYPES]           memoryTypes
    u32                                         memoryHeapCount
    VkMemoryHeap[VK_MAX_MEMORY_HEAPS]           memoryHeaps
}

class VkMemoryAllocateInfo {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO
    const void*                                 pNext                      /// Pointer to next structure
    VkDeviceSize                                allocationSize             /// Size of memory allocation
    u32                                         memoryTypeIndex            /// Index of the of the memory type to allocate from
}

class VkMemoryRequirements {
    VkDeviceSize                                size                       /// Specified in bytes
    VkDeviceSize                                alignment                  /// Specified in bytes
    u32                                         memoryTypeBits             /// Bitfield of the allowed memory type indices into memoryTypes[] for this object
}

class VkSparseImageFormatProperties {
    VkImageAspectFlagBits                       aspectMask
    VkExtent3D                                  imageGranularity
    VkSparseImageFormatFlags                    flags
}

class VkSparseImageMemoryRequirements {
    VkSparseImageFormatProperties               formatProperties
    u32                                         imageMipTailFirstLod
    VkDeviceSize                                imageMipTailSize           /// Specified in bytes, must be a multiple of image block size / alignment
    VkDeviceSize                                imageMipTailOffset         /// Specified in bytes, must be a multiple of image block size / alignment
    VkDeviceSize                                imageMipTailStride         /// Specified in bytes, must be a multiple of image block size / alignment
}

class VkMemoryType {
    VkMemoryPropertyFlags                       propertyFlags              /// Memory properties of this memory type
    u32                                         heapIndex                  /// Index of the memory heap allocations of this memory type are taken from
}

class VkMemoryHeap {
    VkDeviceSize                                size                       /// Available memory in the heap
    VkMemoryHeapFlags                           flags                      /// Flags for the heap
}

class VkMappedMemoryRange {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE
    const void*                                 pNext                      /// Pointer to next structure
    VkDeviceMemory                              memory                     /// Mapped memory object
    VkDeviceSize                                offset                     /// Offset within the mapped memory the range starts from
    VkDeviceSize                                size                       /// Size of the range within the mapped memory
}

class VkFormatProperties {
    VkFormatFeatureFlags                        linearTilingFeatures       /// Format features in case of linear tiling
    VkFormatFeatureFlags                        optimalTilingFeatures      /// Format features in case of optimal tiling
    VkFormatFeatureFlags                        bufferFeatures             /// Format features supported by buffers
}

class VkImageFormatProperties {
    VkExtent3D                                  maxExtent                  /// max image dimensions for this resource type
    u32                                         maxMipLevels               /// max number of mipmap levels for this resource type
    u32                                         maxArrayLayers             /// max array layers for this resource type
    VkSampleCountFlags                          sampleCounts               /// supported sample counts for this resource type
    VkDeviceSize                                maxResourceSize            /// max size (in bytes) of this resource type
}

class VkDescriptorImageInfo {
    VkSampler                                   sampler
    VkImageView                                 imageView
    VkImageLayout                               imageLayout
}

class VkDescriptorBufferInfo {
    VkBuffer                                    buffer                     /// Buffer used for this descriptor when the descriptor is UNIFORM_BUFFER[_DYNAMIC]
    VkDeviceSize                                offset                     /// Base offset from buffer start in bytes to update in the descriptor set.
    VkDeviceSize                                range                      /// Size in bytes of the buffer resource for this descriptor update.
}

class VkWriteDescriptorSet {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET
    const void*                                 pNext                      /// Pointer to next structure
    VkDescriptorSet                             dstSet                     /// Destination descriptor set
    u32                                         dstBinding                 /// Binding within the destination descriptor set to write
    u32                                         dstArrayElement            /// Array element within the destination binding to write
    u32                                         descriptorCount            /// Number of descriptors to write (determines the size of the array pointed by <pDescriptors>)
    VkDescriptorType                            descriptorType             /// Descriptor type to write (determines which fields of the array pointed by <pDescriptors> are going to be used)
    const VkDescriptorImageInfo*                pImageInfo
    const VkDescriptorBufferInfo*               pBufferInfo
    const VkBufferView*                         pTexelBufferView
}

class VkCopyDescriptorSet {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_COPY_DESCRIPTOR_SET
    const void*                                 pNext                      /// Pointer to next structure
    VkDescriptorSet                             srcSet                     /// Source descriptor set
    u32                                         srcBinding                 /// Binding within the source descriptor set to copy from
    u32                                         srcArrayElement            /// Array element within the source binding to copy from
    VkDescriptorSet                             dstSet                     /// Destination descriptor set
    u32                                         dstBinding                 /// Binding within the destination descriptor set to copy to
    u32                                         dstArrayElement            /// Array element within the destination binding to copy to
    u32                                         descriptorCount            /// Number of descriptors to copy
}

class VkBufferCreateInfo {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO
    const void*                                 pNext                      /// Pointer to next structure.
    VkBufferCreateFlags                         flags                      /// Buffer creation flags
    VkDeviceSize                                size                       /// Specified in bytes
    VkBufferUsageFlags                          usage                      /// Buffer usage flags
    VkSharingMode                               sharingMode
    u32                                         queueFamilyIndexCount
    const u32*                                  pQueueFamilyIndices
}

class VkBufferViewCreateInfo {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO
    const void*                                 pNext                      /// Pointer to next structure.
    VkBufferViewCreateFlags                     flags
    VkBuffer                                    buffer
    VkFormat                                    format                     /// Optionally specifies format of elements
    VkDeviceSize                                offset                     /// Specified in bytes
    VkDeviceSize                                range                      /// View size specified in bytes
}

class VkImageSubresource {
    VkImageAspectFlagBits                       aspectMask
    u32                                         mipLevel
    u32                                         arrayLayer
}

class VkImageSubresourceRange {
    VkImageAspectFlags                          aspectMask
    u32                                         baseMipLevel
    u32                                         levelCount
    u32                                         baseArrayLayer
    u32                                         layerCount
}

class VkMemoryBarrier {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_MEMORY_BARRIER
    const void*                                 pNext                      /// Pointer to next structure.
    VkAccessFlags                               srcAccessMask
    VkAccessFlags                               dstAccessMask
}

class VkBufferMemoryBarrier {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER
    const void*                                 pNext                      /// Pointer to next structure.
    VkAccessFlags                               srcAccessMask
    VkAccessFlags                               dstAccessMask
    u32                                         srcQueueFamilyIndex        /// Queue family to transition ownership from
    u32                                         dstQueueFamilyIndex        /// Queue family to transition ownership to
    VkBuffer                                    buffer                     /// Buffer to sync
    VkDeviceSize                                offset                     /// Offset within the buffer to sync
    VkDeviceSize                                size                       /// Amount of bytes to sync
}

class VkImageMemoryBarrier {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER
    const void*                                 pNext                      /// Pointer to next structure.
    VkAccessFlags                               srcAccessMask
    VkAccessFlags                               dstAccessMask
    VkImageLayout                               oldLayout                  /// Current layout of the image
    VkImageLayout                               newLayout                  /// New layout to transition the image to
    u32                                         srcQueueFamilyIndex        /// Queue family to transition ownership from
    u32                                         dstQueueFamilyIndex        /// Queue family to transition ownership to
    VkImage                                     image                      /// Image to sync
    VkImageSubresourceRange                     subresourceRange           /// Subresource range to sync
}

class VkImageCreateInfo {
    VkStructureType                             sType                      /// Must be VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO
    const void*                                 pNext                      /// Pointer to next structure.
    VkImageCreateFlags                          flags                      /// Image creation flags
    VkImageType                                 imageType
    VkFormat                                    format
    VkExtent3D                                  extent
    u32                                         mipLevels
    u32                                         arrayLayers
    VkSampleCountFlagBits                       samples
    VkImageTiling                               tiling
    VkImageUsageFlags                           usage                      /// Image usage flags
    VkSharingMode                               sharingMode                /// Cross-queue-family sharing mode
    u32                                         queueFamilyIndexCount      /// Number of queue families to share across
    const u32*                                  pQueueFamilyIndices        /// Array of queue family indices to share across
    VkImageLayout                               initialLayout              /// Initial image layout for all subresources
}

class VkSubresourceLayout {
    VkDeviceSize                                offset                 /// Specified in bytes
    VkDeviceSize                                size                   /// Specified in bytes
    VkDeviceSize                                rowPitch               /// Specified in bytes
    VkDeviceSize                                arrayPitch             /// Specified in bytes
    VkDeviceSize                                depthPitch             /// Specified in bytes
}

class VkImageViewCreateInfo {
    VkStructureType                             sType                  /// Must be VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO
    const void*                                 pNext                  /// Pointer to next structure
    VkImageViewCreateFlags                      flags
    VkImage                                     image
    VkImageViewType                             viewType
    VkFormat                                    format
    VkComponentMapping                          components
    VkImageSubresourceRange                     subresourceRange
}

class VkBufferCopy {
    VkDeviceSize                                srcOffset              /// Specified in bytes
    VkDeviceSize                                dstOffset              /// Specified in bytes
    VkDeviceSize                                size                   /// Specified in bytes
}

class VkSparseMemoryBind {
    VkDeviceSize                                resourceOffset        /// Specified in bytes
    VkDeviceSize                                size                  /// Specified in bytes
    VkDeviceMemory                              memory
    VkDeviceSize                                memoryOffset          /// Specified in bytes
    VkSparseMemoryBindFlags                     flags
}

class VkSparseImageMemoryBind {
    VkImageSubresource                          subresource
    VkOffset3D                                  offset
    VkExtent3D                                  extent
    VkDeviceMemory                              memory
    VkDeviceSize                                memoryOffset          /// Specified in bytes
    VkSparseMemoryBindFlags                     flags
}

class VkSparseBufferMemoryBindInfo {
    VkBuffer                                    buffer
    u32                                         bindCount
    const VkSparseMemoryBind*                   pBinds
}

class VkSparseImageOpaqueMemoryBindInfo {
    VkImage                                     image
    u32                                         bindCount
    const VkSparseMemoryBind*                   pBinds
}

class VkSparseImageMemoryBindInfo {
    VkImage                                     image
    u32                                         bindCount
    const VkSparseMemoryBind*                   pBinds
}

class VkBindSparseInfo {
    VkStructureType                             sType                 /// Must be VK_STRUCTURE_TYPE_BIND_SPARSE_INFO
    const void*                                 pNext
    u32                                         waitSemaphoreCount
    const VkSemaphore*                          pWaitSemaphores
    u32                                         numBufferBinds
    const VkSparseBufferMemoryBindInfo*         pBufferBinds
    u32                                         numImageOpaqueBinds
    const VkSparseImageOpaqueMemoryBindInfo*    pImageOpaqueBinds
    u32                                         numImageBinds
    const VkSparseImageMemoryBindInfo*          pImageBinds
    u32                                         signalSemaphoreCount
    const VkSemaphore*                          pSignalSemaphores
}

class VkImageSubresourceLayers {
    VkImageAspectFlags                          aspectMask
    u32                                         mipLevel
    u32                                         baseArrayLayer
    u32                                         layerCount
}

class VkImageCopy {
    VkImageSubresourceLayers                    srcSubresource
    VkOffset3D                                  srcOffset             /// Specified in pixels for both compressed and uncompressed images
    VkImageSubresourceLayers                    dstSubresource
    VkOffset3D                                  dstOffset             /// Specified in pixels for both compressed and uncompressed images
    VkExtent3D                                  extent                /// Specified in pixels for both compressed and uncompressed images
}

class VkImageBlit {
    VkImageSubresourceLayers                    srcSubresource
    VkOffset3D[2]                               srcOffsets
    VkImageSubresourceLayers                    dstSubresource
    VkOffset3D[2]                               dstOffsets
}

class VkBufferImageCopy {
    VkDeviceSize                                bufferOffset           /// Specified in bytes
    u32                                         bufferRowLength        /// Specified in texels
    u32                                         bufferImageHeight
    VkImageSubresourceLayers                    imageSubresource
    VkOffset3D                                  imageOffset            /// Specified in pixels for both compressed and uncompressed images
    VkExtent3D                                  imageExtent            /// Specified in pixels for both compressed and uncompressed images
}

class VkImageResolve {
    VkImageSubresourceLayers                    srcSubresource
    VkOffset3D                                  srcOffset
    VkImageSubresourceLayers                    dstSubresource
    VkOffset3D                                  dstOffset
    VkExtent3D                                  extent
}

class VkShaderModuleCreateInfo {
    VkStructureType                             sType                  /// Must be VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO
    const void*                                 pNext                  /// Pointer to next structure
    VkShaderModuleCreateFlags                   flags                  /// Reserved
    platform.size_t                             codeSize               /// Specified in bytes
    const u32*                                  pCode                  /// Binary code of size codeSize
}

class VkDescriptorSetLayoutBinding {
    u32                                         binding
    VkDescriptorType                            descriptorType     /// Type of the descriptors in this binding
    u32                                         descriptorCount    /// Number of descriptors in this binding
    VkShaderStageFlags                          stageFlags         /// Shader stages this binding is visible to
    const VkSampler*                            pImmutableSamplers /// Immutable samplers (used if descriptor type is SAMPLER or COMBINED_IMAGE_SAMPLER, is either NULL or contains <count> number of elements)
}

class VkDescriptorSetLayoutCreateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkDescriptorSetLayoutCreateFlags            flags
    u32                                         bindingCount       /// Number of bindings in the descriptor set layout
    const VkDescriptorSetLayoutBinding*         pBindings          /// Array of descriptor set layout bindings
}

class VkDescriptorPoolSize {
    VkDescriptorType                            type
    u32                                         descriptorCount
}

class VkDescriptorPoolCreateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkDescriptorPoolCreateFlags                 flags
    u32                                         maxSets
    u32                                         poolSizeCount
    const VkDescriptorPoolSize*                 pPoolSizes
}

class VkDescriptorSetAllocateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkDescriptorPool                            descriptorPool
    u32                                         setCount
    const VkDescriptorSetLayout*                pSetLayouts
}

class VkSpecializationMapEntry {
    u32                                         constantID         /// The SpecConstant ID specified in the BIL
    u32                                         offset             /// Offset of the value in the data block
    platform.size_t                             size               /// Size in bytes of the SpecConstant
}

class VkSpecializationInfo {
    u32                                         mapEntryCount      /// Number of entries in the map
    const VkSpecializationMapEntry*             pMapEntries        /// Array of map entries
    platform.size_t                             dataSize           /// Size in bytes of pData
    const void*                                 pData              /// Pointer to SpecConstant data
}

class VkPipelineShaderStageCreateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkPipelineShaderStageCreateFlags            flags
    VkShaderStageFlagBits                       stage
    VkShaderModule                              module
    const char*                                 pName
    const VkSpecializationInfo*                 pSpecializationInfo
}

class VkComputePipelineCreateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkPipelineCreateFlags                       flags              /// Pipeline creation flags
    VkPipelineShaderStageCreateInfo             stage
    VkPipelineLayout                            layout             /// Interface layout of the pipeline
    VkPipeline                                  basePipelineHandle /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of
    s32                                         basePipelineIndex  /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of
}

class VkVertexInputBindingDescription {
    u32                                         binding               /// Vertex buffer binding id
    u32                                         stride                /// Distance between vertices in bytes (0 = no advancement)
    VkVertexInputRate                           inputRate             /// Rate at which binding is incremented
}

class VkVertexInputAttributeDescription {
    u32                                         location              /// location of the shader vertex attrib
    u32                                         binding               /// Vertex buffer binding id
    VkFormat                                    format                /// format of source data
    u32                                         offset                /// Offset of first element in bytes from base of vertex
}

class VkPipelineVertexInputStateCreateInfo {
    VkStructureType                             sType                           /// Should be VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO
    const void*                                 pNext                           /// Pointer to next structure
    VkPipelineVertexInputStateCreateFlags       flags
    u32                                         vertexBindingDescriptionCount   /// number of bindings
    const VkVertexInputBindingDescription*      pVertexBindingDescriptions
    u32                                         vertexAttributeDescriptionCount /// number of attributes
    const VkVertexInputAttributeDescription*    pVertexAttributeDescriptions
}

class VkPipelineInputAssemblyStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineInputAssemblyStateCreateFlags     flags
    VkPrimitiveTopology                         topology
    VkBool32                                    primitiveRestartEnable
}

class VkPipelineTessellationStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineTessellationStateCreateFlags      flags
    u32                                         patchControlPoints
}

class VkPipelineViewportStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineViewportStateCreateFlags          flags
    u32                                         viewportCount
    const VkViewport*                           pViewports
    u32                                         scissorCount
    const VkRect2D*                             pScissors
}

class VkPipelineRasterizationStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineRasterizationStateCreateFlags     flags
    VkBool32                                    depthClampEnable
    VkBool32                                    rasterizerDiscardEnable
    VkPolygonMode                               polygonMode                   /// optional (GL45)
    VkCullModeFlags                             cullMode
    VkFrontFace                                 frontFace
    VkBool32                                    depthBiasEnable
    f32                                         depthBiasConstantFactor
    f32                                         depthBiasClamp
    f32                                         depthBiasSlopeFactor
    f32                                         lineWidth
}

class VkPipelineMultisampleStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineMultisampleStateCreateFlags       flags
    VkSampleCountFlagBits                       rasterizationSamples       /// Number of samples used for rasterization
    VkBool32                                    sampleShadingEnable        /// optional (GL45)
    f32                                         minSampleShading           /// optional (GL45)
    const VkSampleMask*                         pSampleMask
    VkBool32                                    alphaToCoverageEnable
    VkBool32                                    alphaToOneEnable
}

class VkPipelineColorBlendAttachmentState {
    VkBool32                                    blendEnable
    VkBlendFactor                               srcColorBlendFactor
    VkBlendFactor                               dstColorBlendFactor
    VkBlendOp                                   colorBlendOp
    VkBlendFactor                               srcAlphaBlendFactor
    VkBlendFactor                               dstAlphaBlendFactor
    VkBlendOp                                   alphaBlendOp
    VkColorComponentFlags                       colorWriteMask
}

class VkPipelineColorBlendStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineColorBlendStateCreateFlags        flags
    VkBool32                                    logicOpEnable
    VkLogicOp                                   logicOp
    u32                                         attachmentCount    /// # of pAttachments
    const VkPipelineColorBlendAttachmentState*  pAttachments
    f32[4]                                      blendConstants
}

class VkStencilOpState {
    VkStencilOp                                 failOp
    VkStencilOp                                 passOp
    VkStencilOp                                 depthFailOp
    VkCompareOp                                 compareOp
    u32                                         compareMask
    u32                                         writeMask
    u32                                         reference
}

class VkPipelineDepthStencilStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineDepthStencilStateCreateFlags      flags
    VkBool32                                    depthTestEnable
    VkBool32                                    depthWriteEnable
    VkCompareOp                                 depthCompareOp
    VkBool32                                    depthBoundsTestEnable  /// optional (depth_bounds_test)
    VkBool32                                    stencilTestEnable
    VkStencilOpState                            front
    VkStencilOpState                            back
    f32                                         minDepthBounds
    f32                                         maxDepthBounds
}

class VkPipelineDynamicStateCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkPipelineDynamicStateCreateFlags           flags
    u32                                         dynamicStateCount
    const VkDynamicState*                       pDynamicStates
}

class VkGraphicsPipelineCreateInfo {
    VkStructureType                                 sType               /// Must be VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO
    const void*                                     pNext               /// Pointer to next structure
    VkPipelineCreateFlags                           flags               /// Pipeline creation flags
    u32                                             stageCount
    const VkPipelineShaderStageCreateInfo*          pStages             /// One entry for each active shader stage
    const VkPipelineVertexInputStateCreateInfo*     pVertexInputState
    const VkPipelineInputAssemblyStateCreateInfo*   pInputAssemblyState
    const VkPipelineTessellationStateCreateInfo*    pTessellationState
    const VkPipelineViewportStateCreateInfo*        pViewportState
    const VkPipelineRasterizationStateCreateInfo*   pRasterizationState
    const VkPipelineMultisampleStateCreateInfo*     pMultisampleState
    const VkPipelineDepthStencilStateCreateInfo*    pDepthStencilState
    const VkPipelineColorBlendStateCreateInfo*      pColorBlendState
    const VkPipelineDynamicStateCreateInfo*         pDynamicState
    VkPipelineLayout                                layout              /// Interface layout of the pipeline
    VkRenderPass                                    renderPass
    u32                                             subpass
    VkPipeline                                      basePipelineHandle  /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is nonzero, it specifies the handle of the base pipeline this is a derivative of
    s32                                             basePipelineIndex   /// If VK_PIPELINE_CREATE_DERIVATIVE_BIT is set and this value is not -1, it specifies an index into pCreateInfos of the base pipeline this is a derivative of
}

class VkPipelineCacheCreateInfo {
    VkStructureType                             sType                 /// Must be VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO
    const void*                                 pNext                 /// Pointer to next structure
    VkPipelineCacheCreateFlags                  flags
    platform.size_t                             initialDataSize       /// Size of initial data to populate cache, in bytes
    const void*                                 pInitialData          /// Initial data to populate cache
}

class VkPushConstantRange {
    VkShaderStageFlags                          stageFlags   /// Which stages use the range
    u32                                         offset       /// Start of the range, in bytes
    u32                                         size        /// Length of the range, in bytes
}

class VkPipelineLayoutCreateInfo {
    VkStructureType                             sType                   /// Must be VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
    const void*                                 pNext                   /// Pointer to next structure
    VkPipelineLayoutCreateFlags                 flags
    u32                                         descriptorSetCount      /// Number of descriptor sets interfaced by the pipeline
    const VkDescriptorSetLayout*                pSetLayouts             /// Array of <setCount> number of descriptor set layout objects defining the layout of the
    u32                                         pushConstantRangeCount  /// Number of push-constant ranges used by the pipeline
    const VkPushConstantRange*                  pPushConstantRanges     /// Array of pushConstantRangeCount number of ranges used by various shader stages
}

class VkSamplerCreateInfo {
    VkStructureType                             sType          /// Must be VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO
    const void*                                 pNext          /// Pointer to next structure
    VkSamplerCreateFlags                        flags
    VkFilter                                    magFilter      /// Filter mode for magnification
    VkFilter                                    minFilter      /// Filter mode for minifiation
    VkSamplerMipmapMode                         mipmapMode     /// Mipmap selection mode
    VkSamplerAddressMode                        addressModeU
    VkSamplerAddressMode                        addressModeV
    VkSamplerAddressMode                        addressModeW
    f32                                         mipLodBias
    VkBool32                                    anisotropyEnable
    f32                                         maxAnisotropy
    VkBool32                                    compareEnable
    VkCompareOp                                 compareOp
    f32                                         minLod
    f32                                         maxLod
    VkBorderColor                               borderColor
    VkBool32                                    unnormalizedCoordinates
}

class VkCommandPoolCreateInfo {
    VkStructureType                             sType            /// Must be VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO
    const void*                                 pNext            /// Pointer to next structure
    VkCommandPoolCreateFlags                    flags            /// Command pool creation flags
    u32                                         queueFamilyIndex
}

class VkCommandBufferAllocateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkCommandPool                               commandPool
    VkCommandBufferLevel                        level
    u32                                         commandBufferCount
}

class VkCommandBufferInheritanceInfo {
    VkStructureType                             sType       /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_INHERITANCE_INFO
    const void*                                 pNext       /// Pointer to next structure
    VkRenderPass                                renderPass  /// Render pass for secondary command buffers
    u32                                         subpass
    VkFramebuffer                               framebuffer /// Framebuffer for secondary command buffers
    VkBool32                                    occlusionQueryEnable
    VkQueryControlFlags                         queryFlags
    VkQueryPipelineStatisticFlags               pipelineStatistics
}

class VkCommandBufferBeginInfo {
    VkStructureType                             sType       /// Must be VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO
    const void*                                 pNext       /// Pointer to next structure
    VkCommandBufferUsageFlags                   flags       /// Command buffer usage flags
    const VkCommandBufferInheritanceInfo*       pInheritanceInfo
}

class VkRenderPassBeginInfo {
    VkStructureType                             sType       /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO
    const void*                                 pNext       /// Pointer to next structure
    VkRenderPass                                renderPass
    VkFramebuffer                               framebuffer
    VkRect2D                                    renderArea
    u32                                         clearValueCount
    const VkClearValue*                         pClearValues
}

@union
/// Union allowing specification of floating point, integer, or unsigned integer color data. Actual value selected is based on image/attachment being cleared.
class VkClearColorValue {
    f32[4]                                      float32
    s32[4]                                      int32
    u32[4]                                      uint32
}

class VkClearDepthStencilValue {
    f32                                         depth
    u32                                         stencil
}

@union
/// Union allowing specification of color, depth, and stencil color values. Actual value selected is based on attachment being cleared.
class VkClearValue {
    VkClearColorValue                           color
    VkClearDepthStencilValue                    depthStencil
}

class VkClearAttachment {
    VkImageAspectFlags                          aspectMask
    u32                                         colorAttachment
    VkClearValue                                clearValue
}

class VkAttachmentDescription {
    VkAttachmentDescriptionFlags                flags
    VkFormat                                    format
    VkSampleCountFlagBits                       samples
    VkAttachmentLoadOp                          loadOp          /// Load op for color or depth data
    VkAttachmentStoreOp                         storeOp         /// Store op for color or depth data
    VkAttachmentLoadOp                          stencilLoadOp   /// Load op for stencil data
    VkAttachmentStoreOp                         stencilStoreOp  /// Store op for stencil data
    VkImageLayout                               initialLayout
    VkImageLayout                               finalLayout
}

class VkAttachmentReference {
    u32                                         attachment
    VkImageLayout                               layout
}

class VkSubpassDescription {
    VkSubpassDescriptionFlags                   flags
    VkPipelineBindPoint                         pipelineBindPoint  /// Must be VK_PIPELINE_BIND_POINT_GRAPHICS for now
    u32                                         inputAttachmentCount
    const VkAttachmentReference*                pInputAttachments
    u32                                         colorAttachmentCount
    const VkAttachmentReference*                pColorAttachments
    const VkAttachmentReference*                pResolveAttachments
    const VkAttachmentReference*                pDepthStencilAttachment
    u32                                         preserveAttachmentCount
    const u32*                                  pPreserveAttachments
}

class VkSubpassDependency {
    u32                                         srcSubpass
    u32                                         dstSubpass
    VkPipelineStageFlags                        srcStageMask
    VkPipelineStageFlags                        dstStageMask
    VkAccessFlags                               srcAccessMask
    VkAccessFlags                               dstAccessMask
    VkDependencyFlags                           dependencyFlags
}

class VkRenderPassCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkRenderPassCreateFlags                     flags
    u32                                         attachmentCount
    const VkAttachmentDescription*              pAttachments
    u32                                         subpassCount
    const VkSubpassDescription*                 pSubpasses
    u32                                         dependencyCount
    const VkSubpassDependency*                  pDependencies
}

class VkEventCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_EVENT_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkEventCreateFlags                          flags      /// Event creation flags
}

class VkFenceCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_FENCE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkFenceCreateFlags                          flags      /// Fence creation flags
}

class VkPhysicalDeviceFeatures {
    VkBool32                                    robustBufferAccess                        /// out of bounds buffer accesses are well defined
    VkBool32                                    fullDrawIndexUint32                       /// full 32-bit range of indices for indexed draw calls
    VkBool32                                    imageCubeArray                            /// image views which are arrays of cube maps
    VkBool32                                    independentBlend                          /// blending operations are controlled per-attachment
    VkBool32                                    geometryShader                            /// geometry stage
    VkBool32                                    tessellationShader                        /// tessellation control and evaluation stage
    VkBool32                                    sampleRateShading                         /// per-sample shading and interpolation
    VkBool32                                    dualSrcBlend                              /// blend operations which take two sources
    VkBool32                                    logicOp                                   /// logic operations
    VkBool32                                    multiDrawIndirect                         /// multi draw indirect
    VkBool32                                    drawIndirectFirstInstance
    VkBool32                                    depthClamp                                /// depth clamping
    VkBool32                                    depthBiasClamp                            /// depth bias clamping
    VkBool32                                    fillModeNonSolid                          /// point and wireframe fill modes
    VkBool32                                    depthBounds                               /// depth bounds test
    VkBool32                                    wideLines                                 /// lines with width greater than 1
    VkBool32                                    largePoints                               /// points with size greater than 1
    VkBool32                                    alphaToOne                                /// The fragment alpha channel can be forced to maximum representable alpha value
    VkBool32                                    multiViewport
    VkBool32                                    samplerAnisotropy
    VkBool32                                    textureCompressionETC2                    /// ETC texture compression formats
    VkBool32                                    textureCompressionASTC_LDR                /// ASTC LDR texture compression formats
    VkBool32                                    textureCompressionBC                      /// BC1-7 texture compressed formats
    VkBool32                                    occlusionQueryPrecise
    VkBool32                                    pipelineStatisticsQuery                   /// pipeline statistics query
    VkBool32                                    vertexPipelineStoresAndAtomics
    VkBool32                                    fragmentStoresAndAtomics
    VkBool32                                    shaderTessellationAndGeometryPointSize
    VkBool32                                    shaderImageGatherExtended                 /// texture gather with run-time values and independent offsets
    VkBool32                                    shaderStorageImageExtendedFormats         /// the extended set of formats can be used for storage images
    VkBool32                                    shaderStorageImageMultisample             /// multisample images can be used for storage images
    VkBool32                                    shaderStorageImageReadWithoutFormat
    VkBool32                                    shaderStorageImageWriteWithoutFormat
    VkBool32                                    shaderUniformBufferArrayDynamicIndexing   /// arrays of uniform buffers can be accessed with dynamically uniform indices
    VkBool32                                    shaderSampledImageArrayDynamicIndexing    /// arrays of sampled images can be accessed with dynamically uniform indices
    VkBool32                                    shaderStorageBufferArrayDynamicIndexing   /// arrays of storage buffers can be accessed with dynamically uniform indices
    VkBool32                                    shaderStorageImageArrayDynamicIndexing    /// arrays of storage images can be accessed with dynamically uniform indices
    VkBool32                                    shaderClipDistance                        /// clip distance in shaders
    VkBool32                                    shaderCullDistance                        /// cull distance in shaders
    VkBool32                                    shaderFloat64                             /// 64-bit floats (doubles) in shaders
    VkBool32                                    shaderInt64                               /// 64-bit integers in shaders
    VkBool32                                    shaderInt16                               /// 16-bit integers in shaders
    VkBool32                                    shaderResourceResidency                   /// shader can use texture operations that return resource residency information (requires sparseNonResident support)
    VkBool32                                    shaderResourceMinLod                      /// shader can use texture operations that specify minimum resource LOD
    VkBool32                                    sparseBinding                             /// Sparse resources support: Resource memory can be managed at opaque page level rather than object level
    VkBool32                                    sparseResidencyBuffer                     /// Sparse resources support: GPU can access partially resident buffers
    VkBool32                                    sparseResidencyImage2D                    /// Sparse resources support: GPU can access partially resident 2D (non-MSAA non-DepthStencil) images
    VkBool32                                    sparseResidencyImage3D                    /// Sparse resources support: GPU can access partially resident 3D images
    VkBool32                                    sparseResidency2Samples                   /// Sparse resources support: GPU can access partially resident MSAA 2D images with 2 samples
    VkBool32                                    sparseResidency4Samples                   /// Sparse resources support: GPU can access partially resident MSAA 2D images with 4 samples
    VkBool32                                    sparseResidency8Samples                   /// Sparse resources support: GPU can access partially resident MSAA 2D images with 8 samples
    VkBool32                                    sparseResidency16Samples                  /// Sparse resources support: GPU can access partially resident MSAA 2D images with 16 samples
    VkBool32                                    sparseResidencyAliased                    /// Sparse resources support: GPU can correctly access data aliased into multiple locations (opt-in)
    VkBool32                                    variableMultisampleRate
    VkBool32                                    inheritedQueries
}

class VkPhysicalDeviceLimits {
    /// resource maximum sizes
    u32                                         maxImageDimension1D                       /// max 1D image dimension
    u32                                         maxImageDimension2D                       /// max 2D image dimension
    u32                                         maxImageDimension3D                       /// max 3D image dimension
    u32                                         maxImageDimensionCube                     /// max cubemap image dimension
    u32                                         maxImageArrayLayers                       /// max layers for image arrays
    u32                                         maxTexelBufferElements
    u32                                         maxUniformBufferRange                     /// max uniform buffer size (bytes)
    u32                                         maxStorageBufferRange                     /// max storage buffer size (bytes)
    u32                                         maxPushConstantsSize                      /// max size of the push constants pool (bytes)
    /// memory limits
    u32                                         maxMemoryAllocationCount                  /// max number of device memory allocations supported
    u32                                         maxSamplerAllocationCount
    VkDeviceSize                                bufferImageGranularity                    /// Granularity (in bytes) at which buffers and images can be bound to adjacent memory for simultaneous usage
    VkDeviceSize                                sparseAddressSpaceSize                    /// Total address space available for sparse allocations (bytes)
    /// descriptor set limits
    u32                                         maxBoundDescriptorSets                    /// max number of descriptors sets that can be bound to a pipeline
    u32                                         maxPerStageDescriptorSamplers             /// max num of samplers allowed per-stage in a descriptor set
    u32                                         maxPerStageDescriptorUniformBuffers       /// max num of uniform buffers allowed per-stage in a descriptor set
    u32                                         maxPerStageDescriptorStorageBuffers       /// max num of storage buffers allowed per-stage in a descriptor set
    u32                                         maxPerStageDescriptorSampledImages        /// max num of sampled images allowed per-stage in a descriptor set
    u32                                         maxPerStageDescriptorStorageImages        /// max num of storage images allowed per-stage in a descriptor set
    u32                                         maxPerStageDescriptorInputAttachments
    u32                                         maxPerStageResources
    u32                                         maxDescriptorSetSamplers                  /// max num of samplers allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetUniformBuffers            /// max num of uniform buffers allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetUniformBuffersDynamic     /// max num of dynamic uniform buffers allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetStorageBuffers            /// max num of storage buffers allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetStorageBuffersDynamic     /// max num of dynamic storage buffers allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetSampledImages             /// max num of sampled images allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetStorageImages             /// max num of storage images allowed in all stages in a descriptor set
    u32                                         maxDescriptorSetInputAttachments
    /// vertex stage limits
    u32                                         maxVertexInputAttributes                  /// max num of vertex input attribute slots
    u32                                         maxVertexInputBindings                    /// max num of vertex input binding slots
    u32                                         maxVertexInputAttributeOffset             /// max vertex input attribute offset added to vertex buffer offset
    u32                                         maxVertexInputBindingStride               /// max vertex input binding stride
    u32                                         maxVertexOutputComponents                 /// max num of output components written by vertex shader
    /// tessellation control stage limits
    u32                                         maxTessellationGenerationLevel                  /// max level supported by tess primitive generator
    u32                                         maxTessellationPatchSize                        /// max patch size (vertices)
    u32                                         maxTessellationControlPerVertexInputComponents  /// max num of input components per-vertex in TCS
    u32                                         maxTessellationControlPerVertexOutputComponents /// max num of output components per-vertex in TCS
    u32                                         maxTessellationControlPerPatchOutputComponents  /// max num of output components per-patch in TCS
    u32                                         maxTessellationControlTotalOutputComponents     /// max total num of per-vertex and per-patch output components in TCS
    u32                                         maxTessellationEvaluationInputComponents        /// max num of input components per vertex in TES
    u32                                         maxTessellationEvaluationOutputComponents       /// max num of output components per vertex in TES
    /// geometry stage limits
    u32                                         maxGeometryShaderInvocations              /// max invocation count supported in geometry shader
    u32                                         maxGeometryInputComponents                /// max num of input components read in geometry stage
    u32                                         maxGeometryOutputComponents               /// max num of output components written in geometry stage
    u32                                         maxGeometryOutputVertices                 /// max num of vertices that can be emitted in geometry stage
    u32                                         maxGeometryTotalOutputComponents          /// max total num of components (all vertices) written in geometry stage
    /// fragment stage limits
    u32                                         maxFragmentInputComponents                /// max num of input compontents read in fragment stage
    u32                                         maxFragmentOutputAttachments              /// max num of output attachments written in fragment stage
    u32                                         maxFragmentDualSrcAttachments             /// max num of output attachments written when using dual source blending
    u32                                         maxFragmentCombinedOutputResources        /// max total num of storage buffers, storage images and output buffers
    /// compute stage limits
    u32                                         maxComputeSharedMemorySize                /// max total storage size of work group local storage (bytes)
    u32[3]                                      maxComputeWorkGroupCount                  /// max num of compute work groups that may be dispatched by a single command (x,y,z)
    u32                                         maxComputeWorkGroupInvocations            /// max total compute invocations in a single local work group
    u32[3]                                      maxComputeWorkGroupSize                   /// max local size of a compute work group (x,y,z)

    u32                                         subPixelPrecisionBits                     /// num bits of subpixel precision in screen x and y
    u32                                         subTexelPrecisionBits                     /// num bits of subtexel precision
    u32                                         mipmapPrecisionBits                       /// num bits of mipmap precision

    u32                                         maxDrawIndexedIndexValue                  /// max index value for indexed draw calls (for 32-bit indices)
    u32                                         maxDrawIndirectCount

    f32                                         maxSamplerLodBias                         /// max absolute sampler level of detail bias
    f32                                         maxSamplerAnisotropy                      /// max degree of sampler anisotropy

    u32                                         maxViewports                              /// max number of active viewports
    u32[2]                                      maxViewportDimensions                     /// max viewport dimensions (x,y)
    f32[2]                                      viewportBoundsRange                       /// viewport bounds range (min,max)
    u32                                         viewportSubPixelBits                      /// num bits of subpixel precision for viewport

    platform.size_t                             minMemoryMapAlignment                     /// min required alignment of pointers returned by MapMemory (bytes)
    VkDeviceSize                                minTexelBufferOffsetAlignment             /// min required alignment for texel buffer offsets (bytes)
    VkDeviceSize                                minUniformBufferOffsetAlignment           /// min required alignment for uniform buffer sizes and offsets (bytes)
    VkDeviceSize                                minStorageBufferOffsetAlignment           /// min required alignment for storage buffer offsets (bytes)

    s32                                         minTexelOffset                            /// min texel offset for OpTextureSampleOffset
    u32                                         maxTexelOffset                            /// max texel offset for OpTextureSampleOffset
    s32                                         minTexelGatherOffset                      /// min texel offset for OpTextureGatherOffset
    u32                                         maxTexelGatherOffset                      /// max texel offset for OpTextureGatherOffset
    f32                                         minInterpolationOffset                    /// furthest negative offset for interpolateAtOffset
    f32                                         maxInterpolationOffset                    /// furthest positive offset for interpolateAtOffset
    u32                                         subPixelInterpolationOffsetBits           /// num of subpixel bits for interpolateAtOffset

    u32                                         maxFramebufferWidth                       /// max width for a framebuffer
    u32                                         maxFramebufferHeight                      /// max height for a framebuffer
    u32                                         maxFramebufferLayers                      /// max layer count for a layered framebuffer
    VkSampleCountFlags                          framebufferColorSampleCounts
    VkSampleCountFlags                          framebufferDepthSampleCounts
    VkSampleCountFlags                          framebufferStencilSampleCounts
    VkSampleCountFlags                          framebufferNoAttachmentSampleCounts
    u32                                         maxColorAttachments                       /// max num of framebuffer color attachments

    VkSampleCountFlags                          sampledImageColorSampleCounts
    VkSampleCountFlags                          sampledImageIntegerSampleCounts
    VkSampleCountFlags                          sampledImageDepthSampleCounts
    VkSampleCountFlags                          sampledImageStencilSampleCounts
    VkSampleCountFlags                          storageImageSampleCounts
    u32                                         maxSampleMaskWords                        /// max num of sample mask words
    VkBool32                                    timestampComputeAndGraphics

    f32                                         timestampPeriod

    u32                                         maxClipDistances                          /// max number of clip distances
    u32                                         maxCullDistances                          /// max number of cull distances
    u32                                         maxCombinedClipAndCullDistances           /// max combined number of user clipping

    u32                                         discreteQueuePriorities

    f32[2]                                      pointSizeRange                            /// range (min,max) of supported point sizes
    f32[2]                                      lineWidthRange                            /// range (min,max) of supported line widths
    f32                                         pointSizeGranularity                      /// granularity of supported point sizes
    f32                                         lineWidthGranularity                      /// granularity of supported line widths
    VkBool32                                    strictLines
    VkBool32                                    standardSampleLocations

    VkDeviceSize                                optimalBufferCopyOffsetAlignment
    VkDeviceSize                                optimalBufferCopyRowPitchAlignment
    VkDeviceSize                                nonCoherentAtomSize
}

class VkPhysicalDeviceSparseProperties {
    VkBool32                                    residencyStandard2DBlockShape             /// Sparse resources support: GPU will access all 2D (single sample) sparse resources using the standard block shapes (based on pixel format)
    VkBool32                                    residencyStandard2DMultisampleBlockShape  /// Sparse resources support: GPU will access all 2D (multisample) sparse resources using the standard block shapes (based on pixel format)
    VkBool32                                    residencyStandard3DBlockShape             /// Sparse resources support: GPU will access all 3D sparse resources using the standard block shapes (based on pixel format)
    VkBool32                                    residencyAlignedMipSize                   /// Sparse resources support: Images with mip-level dimensions that are NOT a multiple of the block size will be placed in the mip tail
    VkBool32                                    residencyNonResidentStrict                /// Sparse resources support: GPU can safely access non-resident regions of a resource, all reads return as if data is 0, writes are discarded
}

class VkSemaphoreCreateInfo {
    VkStructureType                             sType      /// Must be VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO
    const void*                                 pNext      /// Pointer to next structure
    VkSemaphoreCreateFlags                      flags      /// Semaphore creation flags
}

class VkQueryPoolCreateInfo {
    VkStructureType                             sType              /// Must be VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO
    const void*                                 pNext              /// Pointer to next structure
    VkQueryPoolCreateFlags                      flags
    VkQueryType                                 queryType
    u32                                         queryCount
    VkQueryPipelineStatisticFlags               pipelineStatistics /// Optional
}

class VkFramebufferCreateInfo {
    VkStructureType                             sType  /// Must be VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO
    const void*                                 pNext  /// Pointer to next structure
    VkFramebufferCreateFlags                    flags
    VkRenderPass                                renderPass
    u32                                         attachmentCount
    const VkImageView*                          pAttachments
    u32                                         width
    u32                                         height
    u32                                         layers
}

class VkDrawIndirectCommand {
    u32                                         vertexCount
    u32                                         instanceCount
    u32                                         firstVertex
    u32                                         firstInstance
}

class VkDrawIndexedIndirectCommand {
    u32                                         indexCount
    u32                                         instanceCount
    u32                                         firstIndex
    s32                                         vertexOffset
    u32                                         firstInstance
}

class VkDispatchIndirectCommand {
    u32                                         x
    u32                                         y
    u32                                         z
}

@extension("VK_KHR_surface")
class VkSurfaceCapabilitiesKHR {
    u32                                         minImageCount
    u32                                         maxImageCount
    VkExtent2D                                  currentExtent
    VkExtent2D                                  minImageExtent
    VkExtent2D                                  maxImageExtent
    u32                                         maxImageArrayLayers
    VkSurfaceTransformFlagsKHR                  supportedTransforms
    VkSurfaceTransformFlagBitsKHR               currentTransform
    VkCompositeAlphaFlagsKHR                    supportedCompositeAlpha
    VkImageUsageFlags                           supportedUsageFlags
}

@extension("VK_KHR_surface")
class VkSurfaceFormatKHR {
    VkFormat                                    format
    VkColorSpaceKHR                             colorSpace
}

@extension("VK_KHR_swapchain")
class VkSwapchainCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkSwapchainCreateFlagsKHR                   flags
    VkSurfaceKHR                                surface
    u32                                         minImageCount
    VkFormat                                    imageFormat
    VkColorSpaceKHR                             imageColorSpace
    VkExtent2D                                  imageExtent
    u32                                         imageArrayLayers
    VkImageUsageFlags                           imageUsage
    VkSharingMode                               sharingMode
    u32                                         queueFamilyIndexCount
    const u32*                                  pQueueFamilyIndices
    VkSurfaceTransformFlagBitsKHR               preTransform
    VkCompositeAlphaFlagBitsKHR                 compositeAlpha
    VkPresentModeKHR                            presentMode
    VkBool32                                    clipped
    VkSwapchainKHR                              oldSwapchain
}

@extension("VK_KHR_swapchain")
class VkPresentInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    u32                                         waitSemaphoreCount
    const VkSemaphore*                          pWaitSemaphores
    u32                                         swapchainCount
    const VkSwapchainKHR*                       pSwapchains
    const u32*                                  pImageIndices
    VkResult*                                   pResults
}

@extension("VK_KHR_display")
class VkDisplayPropertiesKHR {
    VkDisplayKHR                                display
    const char*                                 displayName
    VkExtent2D                                  physicalDimensions
    VkExtent2D                                  physicalResolution
    VkSurfaceTransformFlagsKHR                  supportedTransforms
    VkBool32                                    planeReorderPossible
    VkBool32                                    persistentContent
}

@extension("VK_KHR_display")
class VkDisplayModeParametersKHR {
    VkExtent2D                                  visibleRegion
    u32                                         refreshRate
}

@extension("VK_KHR_display")
class VkDisplayModePropertiesKHR {
    VkDisplayModeKHR                            displayMode
    VkDisplayModeParametersKHR                  parameters
}

@extension("VK_KHR_display")
class VkDisplayModeCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkDisplayModeCreateFlagsKHR                 flags
    VkDisplayModeParametersKHR                  parameters
}

@extension("VK_KHR_display")
class VkDisplayPlanePropertiesKHR {
    VkDisplayKHR                                currentDisplay
    u32                                         currentStackIndex
}

@extension("VK_KHR_display")
class VkDisplayPlaneCapabilitiesKHR {
    VkDisplayPlaneAlphaFlagsKHR                 supportedAlpha
    VkOffset2D                                  minSrcPosition
    VkOffset2D                                  maxSrcPosition
    VkExtent2D                                  minSrcExtent
    VkExtent2D                                  maxSrcExtent
    VkOffset2D                                  minDstPosition
    VkOffset2D                                  maxDstPosition
    VkExtent2D                                  minDstExtent
    VkExtent2D                                  maxDstExtent
}

@extension("VK_KHR_display")
class VkDisplaySurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkDisplaySurfaceCreateFlagsKHR              flags
    VkDisplayModeKHR                            displayMode
    u32                                         planeIndex
    u32                                         planeStackIndex
    VkSurfaceTransformFlagBitsKHR               transform
    f32                                         globalAlpha
    VkDisplayPlaneAlphaFlagBitsKHR              alphaMode
    VkExtent2D                                  imageExtent
}

@extension("VK_KHR_display_swapchain")
class VkDisplayPresentInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkRect2D                                    srcRect
    VkRect2D                                    dstRect
    VkBool32                                    persistent
}

@extension("VK_KHR_xlib_surface")
class VkXlibSurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkXlibSurfaceCreateFlagsKHR                 flags
    platform.Display*                           dpy
    platform.Window                             window
}

@extension("VK_KHR_xcb_surface")
class VkXcbSurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkXcbSurfaceCreateFlagsKHR                  flags
    platform.xcb_connection_t*                  connection
    platform.xcb_window_t                       window
}

@extension("VK_KHR_wayland_surface")
class VkWaylandSurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkWaylandSurfaceCreateFlagsKHR              flags
    platform.wl_display*                        display
    platform.wl_surface*                        surface
}

@extension("VK_KHR_mir_surface")
class VkMirSurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkMirSurfaceCreateFlagsKHR                  flags
    platform.MirConnection*                     connection
    platform.MirSurface*                        mirSurface
}

@extension("VK_KHR_android_surface")
class VkAndroidSurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkAndroidSurfaceCreateFlagsKHR              flags
    platform.ANativeWindow*                     window
}

@extension("VK_KHR_win32_surface")
class VkWin32SurfaceCreateInfoKHR {
    VkStructureType                             sType
    const void*                                 pNext
    VkWin32SurfaceCreateFlagsKHR                flags
    platform.HINSTANCE                          hinstance
    platform.HWND                               hwnd
}

@extension("VK_ANDROID_native_buffer")
class VkNativeBufferANDROID {
    VkStructureType                             sType
    const void*                                 pNext
    platform.buffer_handle_t                    handle
    int                                         stride
    int                                         format
    int                                         usage
}

@extension("VK_EXT_debug_report")
class VkDebugReportCallbackCreateInfoEXT {
    VkStructureType                             sType
    const void*                                 pNext
    VkDebugReportFlagsEXT                       flags
    PFN_vkDebugReportCallbackEXT                pfnCallback
    void*                                       pUserData
}

@extension("VK_AMD_rasterization_order")
class VkPipelineRasterizationStateRasterizationOrderAMD {
    VkStructureType                             sType
    const void*                                 pNext
    VkRasterizationOrderAMD                     rasterizationOrder
}

@extension("VK_EXT_debug_marker")
class VkDebugMarkerObjectNameInfoEXT {
    VkStructureType                             sType
    const void*                                 pNext
    VkDebugReportObjectTypeEXT                  objectType
    u64                                         object
    const char*                                 pObjectName
}

@extension("VK_EXT_debug_marker")
class VkDebugMarkerObjectTagInfoEXT {
    VkStructureType                             sType
    const void*                                 pNext
    VkDebugReportObjectTypeEXT                  objectType
    u64                                         object
    u64                                         tagName
    platform.size_t                             tagSize
    const void*                                 pTag
}

@extension("VK_EXT_debug_marker")
class VkDebugMarkerMarkerInfoEXT {
    VkStructureType                             sType
    const void*                                 pNext
    const char*                                 pMarkerName
    f32[4]                                      color
}


////////////////
//  Commands  //
////////////////

// Function pointers. TODO: add support for function pointers.

@external type void* PFN_vkVoidFunction
@pfn cmd void vkVoidFunction() {
}

@external type void* PFN_vkAllocationFunction
@pfn cmd void* vkAllocationFunction(
        void*                                       pUserData,
        platform.size_t                             size,
        platform.size_t                             alignment,
        VkSystemAllocationScope                     allocationScope) {
    return ?
}

@external type void* PFN_vkReallocationFunction
@pfn cmd void* vkReallocationFunction(
        void*                                       pUserData,
        void*                                       pOriginal,
        platform.size_t                             size,
        platform.size_t                             alignment,
        VkSystemAllocationScope                     allocationScope) {
    return ?
}

@external type void* PFN_vkFreeFunction
@pfn cmd void vkFreeFunction(
        void*                                       pUserData,
        void*                                       pMemory) {
}

@external type void* PFN_vkInternalAllocationNotification
@pfn cmd void vkInternalAllocationNotification(
        void*                                       pUserData,
        platform.size_t                             size,
        VkInternalAllocationType                    allocationType,
        VkSystemAllocationScope                     allocationScope) {
}

@external type void* PFN_vkInternalFreeNotification
@pfn cmd void vkInternalFreeNotification(
        void*                                       pUserData,
        platform.size_t                             size,
        VkInternalAllocationType                    allocationType,
        VkSystemAllocationScope                     allocationScope) {
}

// Global functions

@threadSafety("system")
cmd VkResult vkCreateInstance(
        const VkInstanceCreateInfo*                 pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkInstance*                                 pInstance) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO)

    instance := ?
    pInstance[0] = instance
    State.Instances[instance] = new!InstanceObject()

    layers := pCreateInfo.ppEnabledLayerNames[0:pCreateInfo.enabledLayerCount]
    extensions := pCreateInfo.ppEnabledExtensionNames[0:pCreateInfo.enabledExtensionCount]

    return ?
}

@threadSafety("system")
cmd void vkDestroyInstance(
        VkInstance                                  instance,
        const VkAllocationCallbacks*                pAllocator) {
    instanceObject := GetInstance(instance)

    State.Instances[instance] = null
}

@threadSafety("system")
cmd VkResult vkEnumeratePhysicalDevices(
        VkInstance                                  instance,
        u32*                                        pPhysicalDeviceCount,
        VkPhysicalDevice*                           pPhysicalDevices) {
    instanceObject := GetInstance(instance)

    physicalDeviceCount := as!u32(?)
    pPhysicalDeviceCount[0] = physicalDeviceCount
    physicalDevices := pPhysicalDevices[0:physicalDeviceCount]

    for i in (0 .. physicalDeviceCount) {
        physicalDevice := ?
        physicalDevices[i] = physicalDevice
        if !(physicalDevice in State.PhysicalDevices) {
            State.PhysicalDevices[physicalDevice] = new!PhysicalDeviceObject(instance: instance)
        }
    }

    return ?
}

cmd PFN_vkVoidFunction vkGetDeviceProcAddr(
        VkDevice                                    device,
        const char*                                 pName) {
    if device != NULL_HANDLE {
        device := GetDevice(device)
    }

    return ?
}

cmd PFN_vkVoidFunction vkGetInstanceProcAddr(
        VkInstance                                  instance,
        const char*                                 pName) {
    if instance != NULL_HANDLE {
        instanceObject := GetInstance(instance)
    }

    return ?
}

cmd void vkGetPhysicalDeviceProperties(
        VkPhysicalDevice                            physicalDevice,
        VkPhysicalDeviceProperties*                 pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    properties := ?
    pProperties[0] = properties
}

cmd void vkGetPhysicalDeviceQueueFamilyProperties(
        VkPhysicalDevice                            physicalDevice,
        u32*                                        pQueueFamilyPropertyCount,
        VkQueueFamilyProperties*                    pQueueFamilyProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    // TODO: Figure out how to express fetch-count-or-properties
    // This version fails 'apic validate' with 'fence not allowed in
    // *semantic.Branch'. Other attempts have failed with the same or other
    // errors.
    // if pQueueFamilyProperties != null {
    //     queuesProperties := pQueueFamilyProperties[0:pCount[0]]
    //     for i in (0 .. pCount[0]) {
    //         queueProperties := as!VkQueueFamilyProperties(?)
    //         queuesProperties[i] = queueProperties
    //    }
    // } else {
    //     count := ?
    //     pCount[0] = count
    // }
}

cmd void vkGetPhysicalDeviceMemoryProperties(
        VkPhysicalDevice                            physicalDevice,
        VkPhysicalDeviceMemoryProperties*           pMemoryProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    memoryProperties := ?
    pMemoryProperties[0] = memoryProperties
}

cmd void vkGetPhysicalDeviceFeatures(
        VkPhysicalDevice                            physicalDevice,
        VkPhysicalDeviceFeatures*                   pFeatures) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    features := ?
    pFeatures[0] = features
}

cmd void vkGetPhysicalDeviceFormatProperties(
        VkPhysicalDevice                            physicalDevice,
        VkFormat                                    format,
        VkFormatProperties*                         pFormatProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    formatProperties := ?
    pFormatProperties[0] = formatProperties
}

cmd VkResult vkGetPhysicalDeviceImageFormatProperties(
        VkPhysicalDevice                            physicalDevice,
        VkFormat                                    format,
        VkImageType                                 type,
        VkImageTiling                               tiling,
        VkImageUsageFlags                           usage,
        VkImageCreateFlags                          flags,
        VkImageFormatProperties*                    pImageFormatProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    imageFormatProperties := ?
    pImageFormatProperties[0] = imageFormatProperties

    return ?
}


// Device functions

@threadSafety("system")
cmd VkResult vkCreateDevice(
        VkPhysicalDevice                            physicalDevice,
        const VkDeviceCreateInfo*                   pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDevice*                                   pDevice) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO)
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    device := ?
    pDevice[0] = device
    State.Devices[device] = new!DeviceObject(physicalDevice: physicalDevice)

    return ?
}

@threadSafety("system")
cmd void vkDestroyDevice(
        VkDevice                                    device,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)

    State.Devices[device] = null
}


// Extension discovery functions

cmd VkResult vkEnumerateInstanceLayerProperties(
        u32*                                        pPropertyCount,
        VkLayerProperties*                          pProperties) {
    count := as!u32(?)
    pPropertyCount[0] = count

    properties := pProperties[0:count]
    for i in (0 .. count) {
        property := ?
        properties[i] = property
    }

    return ?
}

cmd VkResult vkEnumerateInstanceExtensionProperties(
        const char*                                 pLayerName,
        u32*                                        pPropertyCount,
        VkExtensionProperties*                      pProperties) {
    count := as!u32(?)
    pPropertyCount[0] = count

    properties := pProperties[0:count]
    for i in (0 .. count) {
        property := ?
        properties[i] = property
    }

    return ?
}

cmd VkResult vkEnumerateDeviceLayerProperties(
        VkPhysicalDevice                            physicalDevice,
        u32*                                        pPropertyCount,
        VkLayerProperties*                          pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    count := as!u32(?)
    pPropertyCount[0] = count

    properties := pProperties[0:count]
    for i in (0 .. count) {
        property := ?
        properties[i] = property
    }

    return ?
}

cmd VkResult vkEnumerateDeviceExtensionProperties(
        VkPhysicalDevice                            physicalDevice,
        const char*                                 pLayerName,
        u32*                                        pPropertyCount,
        VkExtensionProperties*                      pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    count := as!u32(?)
    pPropertyCount[0] = count

    properties := pProperties[0:count]
    for i in (0 .. count) {
        property := ?
        properties[i] = property
    }

    return ?
}


// Queue functions

@threadSafety("system")
cmd void vkGetDeviceQueue(
        VkDevice                                    device,
        u32                                         queueFamilyIndex,
        u32                                         queueIndex,
        VkQueue*                                    pQueue) {
    deviceObject := GetDevice(device)

    queue := ?
    pQueue[0] = queue

    if !(queue in State.Queues) {
        State.Queues[queue] = new!QueueObject(device: device)
    }
}

@threadSafety("app")
cmd VkResult vkQueueSubmit(
        VkQueue                                     queue,
        u32                                         submitCount,
        const VkSubmitInfo*                         pSubmits,
        VkFence                                     fence) {
    queueObject := GetQueue(queue)

    if fence != NULL_HANDLE {
        fenceObject := GetFence(fence)
        assert(fenceObject.device == queueObject.device)
    }

    // commandBuffers := pcommandBuffers[0:commandBufferCount]
    // for i in (0 .. commandBufferCount) {
    //    commandBuffer := commandBuffers[i]
    //    commandBufferObject := GetCommandBuffer(commandBuffer)
    //    assert(commandBufferObject.device == queueObject.device)
    //
    //    validate("QueueCheck", commandBufferObject.queueFlags in queueObject.flags,
    //        "vkQueueSubmit: enqueued commandBuffer requires missing queue capabilities.")
    // }

    return ?
}

@threadSafety("system")
cmd VkResult vkQueueWaitIdle(
        VkQueue                                     queue) {
    queueObject := GetQueue(queue)

    return ?
}

@threadSafety("system")
cmd VkResult vkDeviceWaitIdle(
        VkDevice                                    device) {
    deviceObject := GetDevice(device)

    return ?
}


// Memory functions

@threadSafety("system")
cmd VkResult vkAllocateMemory(
        VkDevice                                    device,
        const VkMemoryAllocateInfo*                 pAllocateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDeviceMemory*                             pMemory) {
    assert(pAllocateInfo.sType == VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO)
    deviceObject := GetDevice(device)

    memory := ?
    pMemory[0] = memory
    State.DeviceMemories[memory] = new!DeviceMemoryObject(
        device: device,
        allocationSize: pAllocateInfo[0].allocationSize)

    return ?
}

@threadSafety("system")
cmd void vkFreeMemory(
        VkDevice                                    device,
        VkDeviceMemory                              memory,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    memoryObject := GetDeviceMemory(memory)
    assert(memoryObject.device == device)

    // Check that no objects are still bound before freeing.
    validate("MemoryCheck", len(memoryObject.boundObjects) == 0,
        "vkFreeMemory: objects still bound")
    validate("MemoryCheck", len(memoryObject.boundCommandBuffers) == 0,
        "vkFreeMemory: commandBuffers still bound")
    State.DeviceMemories[memory] = null
}

@threadSafety("app")
cmd VkResult vkMapMemory(
        VkDevice                                    device,
        VkDeviceMemory                              memory,
        VkDeviceSize                                offset,
        VkDeviceSize                                size,
        VkMemoryMapFlags                            flags,
        void**                                      ppData) {
    deviceObject := GetDevice(device)
    memoryObject := GetDeviceMemory(memory)
    assert(memoryObject.device == device)

    assert(flags == as!VkMemoryMapFlags(0))
    assert((offset + size) <= memoryObject.allocationSize)

    return ?
}

@threadSafety("app")
cmd void vkUnmapMemory(
        VkDevice                                    device,
        VkDeviceMemory                              memory) {
    deviceObject := GetDevice(device)
    memoryObject := GetDeviceMemory(memory)
    assert(memoryObject.device == device)
}

cmd VkResult vkFlushMappedMemoryRanges(
        VkDevice                                    device,
        u32                                         memoryRangeCount
        const VkMappedMemoryRange*                  pMemoryRanges) {
    deviceObject := GetDevice(device)

    memoryRanges := pMemoryRanges[0:memoryRangeCount]
    for i in (0 .. memoryRangeCount) {
        memoryRange := memoryRanges[i]
        memoryObject := GetDeviceMemory(memoryRange.memory)
        assert(memoryObject.device == device)
        assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize)
    }

    return ?
}

cmd VkResult vkInvalidateMappedMemoryRanges(
        VkDevice                                    device,
        u32                                         memoryRangeCount,
        const VkMappedMemoryRange*                  pMemoryRanges) {
    deviceObject := GetDevice(device)

    memoryRanges := pMemoryRanges[0:memoryRangeCount]
    for i in (0 .. memoryRangeCount) {
        memoryRange := memoryRanges[i]
        memoryObject := GetDeviceMemory(memoryRange.memory)
        assert(memoryObject.device == device)
        assert((memoryRange.offset + memoryRange.size) <= memoryObject.allocationSize)
    }

    return ?
}


// Memory management API functions

cmd void vkGetDeviceMemoryCommitment(
        VkDevice                                    device,
        VkDeviceMemory                              memory,
        VkDeviceSize*                               pCommittedMemoryInBytes) {
    deviceObject := GetDevice(device)

    if memory != NULL_HANDLE {
        memoryObject := GetDeviceMemory(memory)
        assert(memoryObject.device == device)
    }

    committedMemoryInBytes := ?
    pCommittedMemoryInBytes[0] = committedMemoryInBytes
}

cmd void vkGetBufferMemoryRequirements(
        VkDevice                                    device,
        VkBuffer                                    buffer,
        VkMemoryRequirements*                       pMemoryRequirements) {
    deviceObject := GetDevice(device)
    bufferObject := GetBuffer(buffer)
    assert(bufferObject.device == device)
}

cmd VkResult vkBindBufferMemory(
        VkDevice                                    device,
        VkBuffer                                    buffer,
        VkDeviceMemory                              memory,
        VkDeviceSize                                memoryOffset) {
    deviceObject := GetDevice(device)
    bufferObject := GetBuffer(buffer)
    assert(bufferObject.device == device)

    // Unbind buffer from previous memory object, if not VK_NULL_HANDLE.
    if bufferObject.memory != NULL_HANDLE {
        memoryObject := GetDeviceMemory(bufferObject.memory)
        memoryObject.boundObjects[as!u64(buffer)] = null
    }

    // Bind buffer to given memory object, if not VK_NULL_HANDLE.
    if memory != NULL_HANDLE {
        memoryObject := GetDeviceMemory(memory)
        assert(memoryObject.device == device)
        memoryObject.boundObjects[as!u64(buffer)] = memoryOffset
    }
    bufferObject.memory = memory
    bufferObject.memoryOffset = memoryOffset

    return ?
}

cmd void vkGetImageMemoryRequirements(
        VkDevice                                    device,
        VkImage                                     image,
        VkMemoryRequirements*                       pMemoryRequirements) {
    deviceObject := GetDevice(device)
    imageObject := GetImage(image)
    assert(imageObject.device == device)
}

cmd VkResult vkBindImageMemory(
        VkDevice                                    device,
        VkImage                                     image,
        VkDeviceMemory                              memory,
        VkDeviceSize                                memoryOffset) {
    deviceObject := GetDevice(device)
    imageObject := GetImage(image)
    assert(imageObject.device == device)

    // Unbind image from previous memory object, if not VK_NULL_HANDLE.
    if imageObject.memory != NULL_HANDLE {
        memoryObject := GetDeviceMemory(imageObject.memory)
        memoryObject.boundObjects[as!u64(image)] = null
    }

    // Bind image to given memory object, if not VK_NULL_HANDLE.
    if memory != NULL_HANDLE {
        memoryObject := GetDeviceMemory(memory)
        assert(memoryObject.device == device)
        memoryObject.boundObjects[as!u64(image)] = memoryOffset
    }
    imageObject.memory = memory
    imageObject.memoryOffset = memoryOffset

    return ?
}

cmd void vkGetImageSparseMemoryRequirements(
        VkDevice                                    device,
        VkImage                                     image,
        u32*                                        pSparseMemoryRequirementCount,
        VkSparseImageMemoryRequirements*            pSparseMemoryRequirements) {
    deviceObject := GetDevice(device)
    imageObject := GetImage(image)
    assert(imageObject.device == device)
}

cmd void vkGetPhysicalDeviceSparseImageFormatProperties(
        VkPhysicalDevice                            physicalDevice,
        VkFormat                                    format,
        VkImageType                                 type,
        VkSampleCountFlagBits                       samples,
        VkImageUsageFlags                           usage,
        VkImageTiling                               tiling,
        u32*                                        pPropertyCount,
        VkSparseImageFormatProperties*              pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
}

cmd VkResult vkQueueBindSparse(
        VkQueue                                     queue,
        u32                                         bindInfoCount,
        const VkBindSparseInfo*                     pBindInfo,
        VkFence                                     fence) {
    queueObject := GetQueue(queue)

    return ?
}


// Fence functions

@threadSafety("system")
cmd VkResult vkCreateFence(
        VkDevice                                    device,
        const VkFenceCreateInfo*                    pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkFence*                                    pFence) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FENCE_CREATE_INFO)
    deviceObject := GetDevice(device)

    fence := ?
    pFence[0] = fence
    State.Fences[fence] = new!FenceObject(
        device: device, signaled: (pCreateInfo.flags == as!VkFenceCreateFlags(VK_FENCE_CREATE_SIGNALED_BIT)))

    return ?
}

@threadSafety("system")
cmd void vkDestroyFence(
        VkDevice                                    device,
        VkFence                                     fence,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    fenceObject := GetFence(fence)
    assert(fenceObject.device == device)

    State.Fences[fence] = null
}

@threadSafety("system")
cmd VkResult vkResetFences(
        VkDevice                                    device,
        u32                                         fenceCount,
        const VkFence*                              pFences) {
    deviceObject := GetDevice(device)

    fences := pFences[0:fenceCount]
    for i in (0 .. fenceCount) {
        fence := fences[i]
        fenceObject := GetFence(fence)
        assert(fenceObject.device == device)
        fenceObject.signaled = false
    }

    return ?
}

@threadSafety("system")
cmd VkResult vkGetFenceStatus(
        VkDevice                                    device,
        VkFence                                     fence) {
    deviceObject := GetDevice(device)
    fenceObject := GetFence(fence)
    assert(fenceObject.device == device)

    return ?
}

@threadSafety("system")
cmd VkResult vkWaitForFences(
        VkDevice                                    device,
        u32                                         fenceCount,
        const VkFence*                              pFences,
        VkBool32                                    waitAll,
        u64                                         timeout) {  /// timeout in nanoseconds
    deviceObject := GetDevice(device)

    fences := pFences[0:fenceCount]
    for i in (0 .. fenceCount) {
        fence := fences[i]
        fenceObject := GetFence(fence)
        assert(fenceObject.device == device)
    }

    return ?
}


// Queue semaphore functions

@threadSafety("system")
cmd VkResult vkCreateSemaphore(
        VkDevice                                    device,
        const VkSemaphoreCreateInfo*                pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkSemaphore*                                pSemaphore) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO)
    deviceObject := GetDevice(device)

    semaphore := ?
    pSemaphore[0] = semaphore
    State.Semaphores[semaphore] = new!SemaphoreObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroySemaphore(
        VkDevice                                    device,
        VkSemaphore                                 semaphore,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    semaphoreObject := GetSemaphore(semaphore)
    assert(semaphoreObject.device == device)

    State.Semaphores[semaphore] = null
}


// Event functions

@threadSafety("system")
cmd VkResult vkCreateEvent(
        VkDevice                                    device,
        const VkEventCreateInfo*                    pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkEvent*                                    pEvent) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_EVENT_CREATE_INFO)
    deviceObject := GetDevice(device)

    event := ?
    pEvent[0] = event
    State.Events[event] = new!EventObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyEvent(
        VkDevice                                    device,
        VkEvent                                     event,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    eventObject := GetEvent(event)
    assert(eventObject.device == device)

    State.Events[event] = null
}

@threadSafety("system")
cmd VkResult vkGetEventStatus(
        VkDevice                                    device,
        VkEvent                                     event) {
    deviceObject := GetDevice(device)
    eventObject := GetEvent(event)
    assert(eventObject.device == device)

    return ?
}

@threadSafety("system")
cmd VkResult vkSetEvent(
        VkDevice                                    device,
        VkEvent                                     event) {
    deviceObject := GetDevice(device)
    eventObject := GetEvent(event)
    assert(eventObject.device == device)

    return ?
}

@threadSafety("system")
cmd VkResult vkResetEvent(
        VkDevice                                    device,
        VkEvent                                     event) {
    deviceObject := GetDevice(device)
    eventObject := GetEvent(event)
    assert(eventObject.device == device)

    return ?
}


// Query functions

@threadSafety("system")
cmd VkResult vkCreateQueryPool(
        VkDevice                                    device,
        const VkQueryPoolCreateInfo*                pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkQueryPool*                                pQueryPool) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO)
    deviceObject := GetDevice(device)

    queryPool := ?
    pQueryPool[0] = queryPool
    State.QueryPools[queryPool] = new!QueryPoolObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyQueryPool(
        VkDevice                                    device,
        VkQueryPool                                 queryPool,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    queryPoolObject := GetQueryPool(queryPool)
    assert(queryPoolObject.device == device)

    State.QueryPools[queryPool] = null
}

@threadSafety("system")
cmd VkResult vkGetQueryPoolResults(
        VkDevice                                    device,
        VkQueryPool                                 queryPool,
        u32                                         firstQuery,
        u32                                         queryCount,
        platform.size_t                             dataSize,
        void*                                       pData,
        VkDeviceSize                                stride,
        VkQueryResultFlags                          flags) {
    deviceObject := GetDevice(device)
    queryPoolObject := GetQueryPool(queryPool)
    assert(queryPoolObject.device == device)

    data := pData[0:dataSize]

    return ?
}

// Buffer functions

@threadSafety("system")
cmd VkResult vkCreateBuffer(
        VkDevice                                    device,
        const VkBufferCreateInfo*                   pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkBuffer*                                   pBuffer) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO)
    deviceObject := GetDevice(device)

    buffer := ?
    pBuffer[0] = buffer
    State.Buffers[buffer] = new!BufferObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyBuffer(
        VkDevice                                    device,
        VkBuffer                                    buffer,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    bufferObject := GetBuffer(buffer)
    assert(bufferObject.device == device)

    assert(bufferObject.memory == 0)
    State.Buffers[buffer] = null
}


// Buffer view functions

@threadSafety("system")
cmd VkResult vkCreateBufferView(
        VkDevice                                    device,
        const VkBufferViewCreateInfo*               pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkBufferView*                               pView) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_BUFFER_VIEW_CREATE_INFO)
    deviceObject := GetDevice(device)

    bufferObject := GetBuffer(pCreateInfo.buffer)
    assert(bufferObject.device == device)

    view := ?
    pView[0] = view
    State.BufferViews[view] = new!BufferViewObject(device: device, buffer: pCreateInfo.buffer)

    return ?
}

@threadSafety("system")
cmd void vkDestroyBufferView(
        VkDevice                                    device,
        VkBufferView                                bufferView,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    bufferViewObject := GetBufferView(bufferView)
    assert(bufferViewObject.device == device)

    State.BufferViews[bufferView] = null
}


// Image functions

@threadSafety("system")
cmd VkResult vkCreateImage(
        VkDevice                                    device,
        const VkImageCreateInfo*                    pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkImage*                                    pImage) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO)
    deviceObject := GetDevice(device)

    image := ?
    pImage[0] = image
    State.Images[image] = new!ImageObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyImage(
        VkDevice                                    device,
        VkImage                                     image,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    imageObject := GetImage(image)
    assert(imageObject.device == device)

    assert(imageObject.memory == 0)
    State.Images[image] = null
}

cmd void vkGetImageSubresourceLayout(
        VkDevice                                    device,
        VkImage                                     image,
        const VkImageSubresource*                   pSubresource,
        VkSubresourceLayout*                        pLayout) {
    deviceObject := GetDevice(device)
    imageObject := GetImage(image)
    assert(imageObject.device == device)
}


// Image view functions

@threadSafety("system")
cmd VkResult vkCreateImageView(
        VkDevice                                    device,
        const VkImageViewCreateInfo*                pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkImageView*                                pView) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO)
    deviceObject := GetDevice(device)

    imageObject := GetImage(pCreateInfo.image)
    assert(imageObject.device == device)

    view := ?
    pView[0] = view
    State.ImageViews[view] = new!ImageViewObject(device: device, image: pCreateInfo.image)

    return ?
}

@threadSafety("system")
cmd void vkDestroyImageView(
        VkDevice                                    device,
        VkImageView                                 imageView,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    imageViewObject := GetImageView(imageView)
    assert(imageViewObject.device == device)

    State.ImageViews[imageView] = null
}


// Shader functions

cmd VkResult vkCreateShaderModule(
        VkDevice                                    device,
        const VkShaderModuleCreateInfo*             pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkShaderModule*                             pShaderModule) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO)
    deviceObject := GetDevice(device)

    shaderModule := ?
    pShaderModule[0] = shaderModule
    State.ShaderModules[shaderModule] = new!ShaderModuleObject(device: device)

    return ?
}

cmd void vkDestroyShaderModule(
        VkDevice                                    device,
        VkShaderModule                              shaderModule,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    shaderModuleObject := GetShaderModule(shaderModule)
    assert(shaderModuleObject.device == device)

    State.ShaderModules[shaderModule] = null
}


// Pipeline functions

cmd VkResult vkCreatePipelineCache(
        VkDevice                                    device,
        const VkPipelineCacheCreateInfo*            pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkPipelineCache*                            pPipelineCache) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO)
    deviceObject := GetDevice(device)

    pipelineCache := ?
    pPipelineCache[0] = pipelineCache
    State.PipelineCaches[pipelineCache] = new!PipelineCacheObject(device: device)

    return ?
}

cmd void vkDestroyPipelineCache(
        VkDevice                                    device,
        VkPipelineCache                             pipelineCache,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    pipelineCacheObject := GetPipelineCache(pipelineCache)
    assert(pipelineCacheObject.device == device)

    State.PipelineCaches[pipelineCache] = null
}

cmd VkResult vkGetPipelineCacheData(
        VkDevice                                    device,
        VkPipelineCache                             pipelineCache,
        platform.size_t*                            pDataSize,
        void*                                       pData) {
    deviceObject := GetDevice(device)
    pipelineCacheObject := GetPipelineCache(pipelineCache)
    assert(pipelineCacheObject.device == device)

    return ?
}

cmd VkResult vkMergePipelineCaches(
        VkDevice                                    device,
        VkPipelineCache                             dstCache,
        u32                                         srcCacheCount,
        const VkPipelineCache*                      pSrcCaches) {
    deviceObject := GetDevice(device)
    dstCacheObject := GetPipelineCache(dstCache)
    assert(dstCacheObject.device == device)

    srcCaches := pSrcCaches[0:srcCacheCount]
    for i in (0 .. srcCacheCount) {
        srcCache := srcCaches[i]
        srcCacheObject := GetPipelineCache(srcCache)
        assert(srcCacheObject.device == device)
    }

    return ?
}

cmd VkResult vkCreateGraphicsPipelines(
        VkDevice                                    device,
        VkPipelineCache                             pipelineCache,
        u32                                         createInfoCount,
        const VkGraphicsPipelineCreateInfo*         pCreateInfos,
        const VkAllocationCallbacks*                pAllocator,
        VkPipeline*                                 pPipelines) {
    deviceObject := GetDevice(device)
    if pipelineCache != NULL_HANDLE {
        pipelineCacheObject := GetPipelineCache(pipelineCache)
        assert(pipelineCacheObject.device == device)
    }

    createInfos := pCreateInfos[0:createInfoCount]
    pipelines := pPipelines[0:createInfoCount]
    for i in (0 .. createInfoCount) {
        pipeline := ?
        pipelines[i] = pipeline
        State.Pipelines[pipeline] = new!PipelineObject(device: device)
    }

    return ?
}

cmd VkResult vkCreateComputePipelines(
        VkDevice                                    device,
        VkPipelineCache                             pipelineCache,
        u32                                         createInfoCount,
        const VkComputePipelineCreateInfo*          pCreateInfos,
        const VkAllocationCallbacks*                pAllocator,
        VkPipeline*                                 pPipelines) {
    deviceObject := GetDevice(device)
    if pipelineCache != NULL_HANDLE {
        pipelineCacheObject := GetPipelineCache(pipelineCache)
        assert(pipelineCacheObject.device == device)
    }

    createInfos := pCreateInfos[0:createInfoCount]
    pipelines := pPipelines[0:createInfoCount]
    for i in (0 .. createInfoCount) {
        pipeline := ?
        pipelines[i] = pipeline
        State.Pipelines[pipeline] = new!PipelineObject(device: device)
    }

    return ?
}

@threadSafety("system")
cmd void vkDestroyPipeline(
        VkDevice                                    device,
        VkPipeline                                  pipeline,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    pipelineObjects := GetPipeline(pipeline)
    assert(pipelineObjects.device == device)

    State.Pipelines[pipeline] = null
}


// Pipeline layout functions

@threadSafety("system")
cmd VkResult vkCreatePipelineLayout(
        VkDevice                                    device,
        const VkPipelineLayoutCreateInfo*           pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkPipelineLayout*                           pPipelineLayout) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO)
    deviceObject := GetDevice(device)

    pipelineLayout := ?
    pPipelineLayout[0] = pipelineLayout
    State.PipelineLayouts[pipelineLayout] = new!PipelineLayoutObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyPipelineLayout(
        VkDevice                                    device,
        VkPipelineLayout                            pipelineLayout,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    pipelineLayoutObjects := GetPipelineLayout(pipelineLayout)
    assert(pipelineLayoutObjects.device == device)

    State.PipelineLayouts[pipelineLayout] = null
}


// Sampler functions

@threadSafety("system")
cmd VkResult vkCreateSampler(
        VkDevice                                    device,
        const VkSamplerCreateInfo*                  pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkSampler*                                  pSampler) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO)
    deviceObject := GetDevice(device)

    sampler := ?
    pSampler[0] = sampler
    State.Samplers[sampler] = new!SamplerObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroySampler(
        VkDevice                                    device,
        VkSampler                                   sampler,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    samplerObject := GetSampler(sampler)
    assert(samplerObject.device == device)

    State.Samplers[sampler] = null
}


// Descriptor set functions

@threadSafety("system")
cmd VkResult vkCreateDescriptorSetLayout(
        VkDevice                                    device,
        const VkDescriptorSetLayoutCreateInfo*      pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDescriptorSetLayout*                      pSetLayout) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO)
    deviceObject := GetDevice(device)

    setLayout := ?
    pSetLayout[0] = setLayout
    State.DescriptorSetLayouts[setLayout] = new!DescriptorSetLayoutObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyDescriptorSetLayout(
        VkDevice                                    device,
        VkDescriptorSetLayout                       descriptorSetLayout,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    descriptorSetLayoutObject := GetDescriptorSetLayout(descriptorSetLayout)
    assert(descriptorSetLayoutObject.device == device)

    State.DescriptorSetLayouts[descriptorSetLayout] = null
}

@threadSafety("system")
cmd VkResult vkCreateDescriptorPool(
        VkDevice                                    device,
        const VkDescriptorPoolCreateInfo*           pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDescriptorPool*                           pDescriptorPool) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO)
    deviceObject := GetDevice(device)

    descriptorPool := ?
    pDescriptorPool[0] = descriptorPool
    State.DescriptorPools[descriptorPool] = new!DescriptorPoolObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyDescriptorPool(
        VkDevice                                    device,
        VkDescriptorPool                            descriptorPool,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    descriptorPoolObject := GetDescriptorPool(descriptorPool)
    assert(descriptorPoolObject.device == device)

    State.DescriptorPools[descriptorPool] = null
}

@threadSafety("app")
cmd VkResult vkResetDescriptorPool(
        VkDevice                                    device,
        VkDescriptorPool                            descriptorPool,
        VkDescriptorPoolResetFlags                  flags) {
    deviceObject := GetDevice(device)
    descriptorPoolObject := GetDescriptorPool(descriptorPool)
    assert(descriptorPoolObject.device == device)

    return ?
}

@threadSafety("app")
cmd VkResult vkAllocateDescriptorSets(
        VkDevice                                    device,
        const VkDescriptorSetAllocateInfo*          pAllocateInfo,
        VkDescriptorSet*                            pDescriptorSets) {
    deviceObject := GetDevice(device)
    allocInfo := pAllocateInfo[0]
    descriptorPoolObject := GetDescriptorPool(allocInfo.descriptorPool)

    setLayouts := allocInfo.pSetLayouts[0:allocInfo.setCount]
    for i in (0 .. allocInfo.setCount) {
        setLayout := setLayouts[i]
        setLayoutObject := GetDescriptorSetLayout(setLayout)
        assert(setLayoutObject.device == device)
    }

    descriptorSets := pDescriptorSets[0:allocInfo.setCount]
    for i in (0 .. allocInfo.setCount) {
        descriptorSet := ?
        descriptorSets[i] = descriptorSet
        State.DescriptorSets[descriptorSet] = new!DescriptorSetObject(device: device)
    }

    return ?
}

cmd VkResult vkFreeDescriptorSets(
        VkDevice                                    device,
        VkDescriptorPool                            descriptorPool,
        u32                                         descriptorSetCount,
        const VkDescriptorSet*                      pDescriptorSets) {
    deviceObject := GetDevice(device)
    descriptorPoolObject := GetDescriptorPool(descriptorPool)

    descriptorSets := pDescriptorSets[0:descriptorSetCount]
    for i in (0 .. descriptorSetCount) {
        descriptorSet := descriptorSets[i]
        descriptorSetObject := GetDescriptorSet(descriptorSet)
        assert(descriptorSetObject.device == device)
        State.DescriptorSets[descriptorSet] = null
    }

    return ?
}

cmd void vkUpdateDescriptorSets(
        VkDevice                                    device,
        u32                                         descriptorWriteCount,
        const VkWriteDescriptorSet*                 pDescriptorWrites,
        u32                                         descriptorCopyCount,
        const VkCopyDescriptorSet*                  pDescriptorCopies) {
    deviceObject := GetDevice(device)

    descriptorWrites := pDescriptorWrites[0:descriptorWriteCount]
    for i in (0 .. descriptorWriteCount) {
        descriptorWrite := descriptorWrites[i]
        descriptorWriteObject := GetDescriptorSet(descriptorWrite.dstSet)
        assert(descriptorWriteObject.device == device)
    }

    descriptorCopies := pDescriptorCopies[0:descriptorCopyCount]
    for i in (0 .. descriptorCopyCount) {
        descriptorCopy := descriptorCopies[i]
        descriptorCopyObject := GetDescriptorSet(descriptorCopy.dstSet)
        assert(descriptorCopyObject.device == device)
    }
}


// Framebuffer functions

@threadSafety("system")
cmd VkResult vkCreateFramebuffer(
        VkDevice                                    device,
        const VkFramebufferCreateInfo*              pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkFramebuffer*                              pFramebuffer) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO)
    deviceObject := GetDevice(device)

    framebuffer := ?
    pFramebuffer[0] = framebuffer
    State.Framebuffers[framebuffer] = new!FramebufferObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyFramebuffer(
        VkDevice                                    device,
        VkFramebuffer                               framebuffer,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    framebufferObject := GetFramebuffer(framebuffer)
    assert(framebufferObject.device == device)

    State.Framebuffers[framebuffer] = null
}


// Renderpass functions

@threadSafety("system")
cmd VkResult vkCreateRenderPass(
        VkDevice                                    device,
        const VkRenderPassCreateInfo*               pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkRenderPass*                               pRenderPass) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO)
    deviceObject := GetDevice(device)

    renderpass := ?
    pRenderPass[0] = renderpass
    State.RenderPasses[renderpass] = new!RenderPassObject(device: device)

    return ?
}

@threadSafety("system")
cmd void vkDestroyRenderPass(
        VkDevice                                    device,
        VkRenderPass                                renderPass,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    renderPassObject := GetRenderPass(renderPass)
    assert(renderPassObject.device == device)

    State.RenderPasses[renderPass] = null
}

cmd void vkGetRenderAreaGranularity(
        VkDevice                                    device,
        VkRenderPass                                renderPass,
        VkExtent2D*                                 pGranularity) {
    deviceObject := GetDevice(device)
    renderPassObject := GetRenderPass(renderPass)

    granularity := ?
    pGranularity[0] = granularity
}

// Command pool functions

cmd VkResult vkCreateCommandPool(
        VkDevice                                    device,
        const VkCommandPoolCreateInfo*              pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkCommandPool*                              pCommandPool) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO)
    deviceObject := GetDevice(device)

    commandPool := ?
    pCommandPool[0] = commandPool
    State.CommandPools[commandPool] = new!CommandPoolObject(device: device)

    return ?
}

cmd void vkDestroyCommandPool(
        VkDevice                                    device,
        VkCommandPool                               commandPool,
        const VkAllocationCallbacks*                pAllocator) {
    deviceObject := GetDevice(device)
    commandPoolObject := GetCommandPool(commandPool)
    assert(commandPoolObject.device == device)

    State.CommandPools[commandPool] = null
}

cmd VkResult vkResetCommandPool(
        VkDevice                                    device,
        VkCommandPool                               commandPool,
        VkCommandPoolResetFlags                     flags) {
    deviceObject := GetDevice(device)
    commandPoolObject := GetCommandPool(commandPool)
    assert(commandPoolObject.device == device)

    return ?
}

// Command buffer functions

macro void bindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) {
    memoryObject := GetDeviceMemory(memory)
    memoryObject.boundCommandBuffers[commandBuffer] = commandBuffer

    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.boundObjects[as!u64(obj)] = memory
}

macro void unbindCommandBuffer(VkCommandBuffer commandBuffer, any obj, VkDeviceMemory memory) {
    memoryObject := GetDeviceMemory(memory)
    memoryObject.boundCommandBuffers[commandBuffer] = null

    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.boundObjects[as!u64(obj)] = null
}

@threadSafety("system")
cmd VkResult vkAllocateCommandBuffers(
        VkDevice                                    device,
        const VkCommandBufferAllocateInfo*          pAllocateInfo,
        VkCommandBuffer*                            pCommandBuffers) {
    assert(pAllocateInfo[0].sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO)

    count := pAllocateInfo[0].commandBufferCount
    commandBuffers := pCommandBuffers[0:count]
    for i in (0 .. count) {
        commandBuffer := ?
        commandBuffers[i] = commandBuffer
        State.CommandBuffers[commandBuffer] = new!CommandBufferObject(device: device)
    }

    return ?
}

@threadSafety("system")
cmd void vkFreeCommandBuffers(
        VkDevice                                    device,
        VkCommandPool                               commandPool,
        u32                                         commandBufferCount,
        const VkCommandBuffer*                      pCommandBuffers) {
    deviceObject := GetDevice(device)

    commandBuffers := pCommandBuffers[0:commandBufferCount]
    for i in (0 .. commandBufferCount) {
        commandBufferObject := GetCommandBuffer(commandBuffers[i])
        assert(commandBufferObject.device == device)
        // TODO: iterate over boundObjects and clear memory bindings
        State.CommandBuffers[commandBuffers[i]] = null
    }
}

@threadSafety("app")
cmd VkResult vkBeginCommandBuffer(
        VkCommandBuffer                             commandBuffer,
        const VkCommandBufferBeginInfo*             pBeginInfo) {
    assert(pBeginInfo.sType == VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO)
    commandBufferObject := GetCommandBuffer(commandBuffer)

    // TODO: iterate over boundObjects and clear memory bindings

    return ?
}

@threadSafety("app")
cmd VkResult vkEndCommandBuffer(
        VkCommandBuffer                             commandBuffer) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    return ?
}

@threadSafety("app")
cmd VkResult vkResetCommandBuffer(
        VkCommandBuffer                             commandBuffer,
        VkCommandBufferResetFlags                   flags) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    // TODO: iterate over boundObjects and clear memory bindings

    return ?
}


// Command buffer building functions

@threadSafety("app")
cmd void vkCmdBindPipeline(
        VkCommandBuffer                             commandBuffer,
        VkPipelineBindPoint                         pipelineBindPoint,
        VkPipeline                                  pipeline) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    pipelineObject := GetPipeline(pipeline)
    assert(commandBufferObject.device == pipelineObject.device)

    queue := switch (pipelineBindPoint) {
        case VK_PIPELINE_BIND_POINT_COMPUTE:  VK_QUEUE_COMPUTE_BIT
        case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT
    }
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue)
}

@threadSafety("app")
cmd void vkCmdSetViewport(
        VkCommandBuffer                             commandBuffer,
        u32                                         firstViewport,
        u32                                         viewportCount,
        const VkViewport*                           pViewports) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetScissor(
        VkCommandBuffer                             commandBuffer,
        u32                                         firstScissor,
        u32                                         scissorCount,
        const VkRect2D*                             pScissors) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetLineWidth(
        VkCommandBuffer                             commandBuffer,
        f32                                         lineWidth) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetDepthBias(
        VkCommandBuffer                             commandBuffer,
        f32                                         depthBiasConstantFactor,
        f32                                         depthBiasClamp,
        f32                                         depthBiasSlopeFactor) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetBlendConstants(
        VkCommandBuffer                             commandBuffer,
        // TODO(jessehall): apic only supports 'const' on pointer types. Using
        // an annotation as a quick hack to pass this to the template without
        // having to modify the AST and semantic model.
        @readonly f32[4]                            blendConstants) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetDepthBounds(
        VkCommandBuffer                             commandBuffer,
        f32                                         minDepthBounds,
        f32                                         maxDepthBounds) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetStencilCompareMask(
        VkCommandBuffer                             commandBuffer,
        VkStencilFaceFlags                          faceMask,
        u32                                         compareMask) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetStencilWriteMask(
        VkCommandBuffer                             commandBuffer,
        VkStencilFaceFlags                          faceMask,
        u32                                         writeMask) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetStencilReference(
        VkCommandBuffer                             commandBuffer,
        VkStencilFaceFlags                          faceMask,
        u32                                         reference) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdBindDescriptorSets(
        VkCommandBuffer                             commandBuffer,
        VkPipelineBindPoint                         pipelineBindPoint,
        VkPipelineLayout                            layout,
        u32                                         firstSet,
        u32                                         descriptorSetCount,
        const VkDescriptorSet*                      pDescriptorSets,
        u32                                         dynamicOffsetCount,
        const u32*                                  pDynamicOffsets) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    descriptorSets := pDescriptorSets[0:descriptorSetCount]
    for i in (0 .. descriptorSetCount) {
        descriptorSet := descriptorSets[i]
        descriptorSetObject := GetDescriptorSet(descriptorSet)
        assert(commandBufferObject.device == descriptorSetObject.device)
    }

    dynamicOffsets := pDynamicOffsets[0:dynamicOffsetCount]
    for i in (0 .. dynamicOffsetCount) {
        dynamicOffset := dynamicOffsets[i]
    }

    queue := switch (pipelineBindPoint) {
        case VK_PIPELINE_BIND_POINT_COMPUTE:  VK_QUEUE_COMPUTE_BIT
        case VK_PIPELINE_BIND_POINT_GRAPHICS: VK_QUEUE_GRAPHICS_BIT
    }
    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, queue)
}

@threadSafety("app")
cmd void vkCmdBindIndexBuffer(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    buffer,
        VkDeviceSize                                offset,
        VkIndexType                                 indexType) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    bufferObject := GetBuffer(buffer)
    assert(commandBufferObject.device == bufferObject.device)

    bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdBindVertexBuffers(
        VkCommandBuffer                             commandBuffer,
        u32                                         firstBinding,
        u32                                         bindingCount,
        const VkBuffer*                             pBuffers,
        const VkDeviceSize*                         pOffsets) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    // TODO: check if not [firstBinding:firstBinding+bindingCount]
    buffers := pBuffers[0:bindingCount]
    offsets := pOffsets[0:bindingCount]
    for i in (0 .. bindingCount) {
        buffer := buffers[i]
        offset := offsets[i]
        bufferObject := GetBuffer(buffer)
        assert(commandBufferObject.device == bufferObject.device)

        bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)
    }

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdDraw(
        VkCommandBuffer                             commandBuffer,
        u32                                         vertexCount,
        u32                                         instanceCount,
        u32                                         firstVertex,
        u32                                         firstInstance) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdDrawIndexed(
        VkCommandBuffer                             commandBuffer,
        u32                                         indexCount,
        u32                                         instanceCount,
        u32                                         firstIndex,
        s32                                         vertexOffset,
        u32                                         firstInstance) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdDrawIndirect(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    buffer,
        VkDeviceSize                                offset,
        u32                                         drawCount,
        u32                                         stride) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    bufferObject := GetBuffer(buffer)
    assert(commandBufferObject.device == bufferObject.device)

    bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdDrawIndexedIndirect(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    buffer,
        VkDeviceSize                                offset,
        u32                                         drawCount,
        u32                                         stride) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    bufferObject := GetBuffer(buffer)
    assert(commandBufferObject.device == bufferObject.device)

    bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdDispatch(
        VkCommandBuffer                             commandBuffer,
        u32                                         x,
        u32                                         y,
        u32                                         z) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT)
}

@threadSafety("app")
cmd void vkCmdDispatchIndirect(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    buffer,
        VkDeviceSize                                offset) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    bufferObject := GetBuffer(buffer)
    assert(commandBufferObject.device == bufferObject.device)

    bindCommandBuffer(commandBuffer, buffer, bufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_COMPUTE_BIT)
}

@threadSafety("app")
cmd void vkCmdCopyBuffer(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    srcBuffer,
        VkBuffer                                    dstBuffer,
        u32                                         regionCount,
        const VkBufferCopy*                         pRegions) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcBufferObject := GetBuffer(srcBuffer)
    dstBufferObject := GetBuffer(dstBuffer)
    assert(commandBufferObject.device == srcBufferObject.device)
    assert(commandBufferObject.device == dstBufferObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory)
    bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdCopyImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     srcImage,
        VkImageLayout                               srcImageLayout,
        VkImage                                     dstImage,
        VkImageLayout                               dstImageLayout,
        u32                                         regionCount,
        const VkImageCopy*                          pRegions) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcImageObject := GetImage(srcImage)
    dstImageObject := GetImage(dstImage)
    assert(commandBufferObject.device == srcImageObject.device)
    assert(commandBufferObject.device == dstImageObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
    bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdBlitImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     srcImage,
        VkImageLayout                               srcImageLayout,
        VkImage                                     dstImage,
        VkImageLayout                               dstImageLayout,
        u32                                         regionCount,
        const VkImageBlit*                          pRegions,
        VkFilter                                    filter) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcImageObject := GetImage(srcImage)
    dstImageObject := GetImage(dstImage)
    assert(commandBufferObject.device == srcImageObject.device)
    assert(commandBufferObject.device == dstImageObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
    bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdCopyBufferToImage(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    srcBuffer,
        VkImage                                     dstImage,
        VkImageLayout                               dstImageLayout,
        u32                                         regionCount,
        const VkBufferImageCopy*                    pRegions) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcBufferObject := GetBuffer(srcBuffer)
    dstImageObject := GetImage(dstImage)
    assert(commandBufferObject.device == srcBufferObject.device)
    assert(commandBufferObject.device == dstImageObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcBuffer, srcBufferObject.memory)
    bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdCopyImageToBuffer(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     srcImage,
        VkImageLayout                               srcImageLayout,
        VkBuffer                                    dstBuffer,
        u32                                         regionCount,
        const VkBufferImageCopy*                    pRegions) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcImageObject := GetImage(srcImage)
    dstBufferObject := GetBuffer(dstBuffer)
    assert(commandBufferObject.device == srcImageObject.device)
    assert(commandBufferObject.device == dstBufferObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
    bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdUpdateBuffer(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    dstBuffer,
        VkDeviceSize                                dstOffset,
        VkDeviceSize                                dataSize,
        const u32*                                  pData) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    dstBufferObject := GetBuffer(dstBuffer)
    assert(commandBufferObject.device == dstBufferObject.device)

    data := pData[0:dataSize]

    bindCommandBuffer(commandBuffer, dstBuffer, dstBufferObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdFillBuffer(
        VkCommandBuffer                             commandBuffer,
        VkBuffer                                    dstBuffer,
        VkDeviceSize                                dstOffset,
        VkDeviceSize                                size,
        u32                                         data) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    dstBufferObject := GetBuffer(dstBuffer)
    assert(commandBufferObject.device == dstBufferObject.device)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_TRANSFER_BIT)
}

@threadSafety("app")
cmd void vkCmdClearColorImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     image,
        VkImageLayout                               imageLayout,
        const VkClearColorValue*                    pColor,
        u32                                         rangeCount,
        const VkImageSubresourceRange*              pRanges) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    imageObject := GetImage(image)
    assert(commandBufferObject.device == imageObject.device)

    ranges := pRanges[0:rangeCount]
    for i in (0 .. rangeCount) {
        range := ranges[i]
    }

    bindCommandBuffer(commandBuffer, image, imageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdClearDepthStencilImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     image,
        VkImageLayout                               imageLayout,
        const VkClearDepthStencilValue*             pDepthStencil,
        u32                                         rangeCount,
        const VkImageSubresourceRange*              pRanges) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    imageObject := GetImage(image)
    assert(commandBufferObject.device == imageObject.device)

    ranges := pRanges[0:rangeCount]
    for i in (0 .. rangeCount) {
        range := ranges[i]
    }

    bindCommandBuffer(commandBuffer, image, imageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdClearAttachments(
        VkCommandBuffer                             commandBuffer,
        u32                                         attachmentCount,
        const VkClearAttachment*                    pAttachments,
        u32                                         rectCount,
        const VkClearRect*                          pRects) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    rects := pRects[0:rectCount]
    for i in (0 .. rectCount) {
        rect := rects[i]
    }

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdResolveImage(
        VkCommandBuffer                             commandBuffer,
        VkImage                                     srcImage,
        VkImageLayout                               srcImageLayout,
        VkImage                                     dstImage,
        VkImageLayout                               dstImageLayout,
        u32                                         regionCount,
        const VkImageResolve*                       pRegions) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    srcImageObject := GetImage(srcImage)
    dstImageObject := GetImage(dstImage)
    assert(commandBufferObject.device == srcImageObject.device)
    assert(commandBufferObject.device == dstImageObject.device)

    regions := pRegions[0:regionCount]
    for i in (0 .. regionCount) {
        region := regions[i]
    }

    bindCommandBuffer(commandBuffer, srcImage, srcImageObject.memory)
    bindCommandBuffer(commandBuffer, dstImage, dstImageObject.memory)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

@threadSafety("app")
cmd void vkCmdSetEvent(
        VkCommandBuffer                             commandBuffer,
        VkEvent                                     event,
        VkPipelineStageFlags                        stageMask) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    eventObject := GetEvent(event)
    assert(commandBufferObject.device == eventObject.device)
}

@threadSafety("app")
cmd void vkCmdResetEvent(
        VkCommandBuffer                             commandBuffer,
        VkEvent                                     event,
        VkPipelineStageFlags                        stageMask) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    eventObject := GetEvent(event)
    assert(commandBufferObject.device == eventObject.device)
}

@threadSafety("app")
cmd void vkCmdWaitEvents(
        VkCommandBuffer                             commandBuffer,
        u32                                         eventCount,
        const VkEvent*                              pEvents,
        VkPipelineStageFlags                        srcStageMask,
        VkPipelineStageFlags                        dstStageMask,
        u32                                         memoryBarrierCount,
        const VkMemoryBarrier*                      pMemoryBarriers,
        u32                                         bufferMemoryBarrierCount,
        const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
        u32                                         imageMemoryBarrierCount,
        const VkImageMemoryBarrier*                 pImageMemoryBarriers) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    events := pEvents[0:eventCount]
    for i in (0 .. eventCount) {
        event := events[i]
        eventObject := GetEvent(event)
        assert(commandBufferObject.device == eventObject.device)
    }

    memoryBarriers := pMemoryBarriers[0:memoryBarrierCount]
    for i in (0 .. memoryBarrierCount) {
        memoryBarrier := memoryBarriers[i]
    }
    bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount]
    for i in (0 .. bufferMemoryBarrierCount) {
        bufferMemoryBarrier := bufferMemoryBarriers[i]
        bufferObject := GetBuffer(bufferMemoryBarrier.buffer)
        assert(bufferObject.device == commandBufferObject.device)
    }
    imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount]
    for i in (0 .. imageMemoryBarrierCount) {
        imageMemoryBarrier := imageMemoryBarriers[i]
        imageObject := GetImage(imageMemoryBarrier.image)
        assert(imageObject.device == commandBufferObject.device)
    }
}

@threadSafety("app")
cmd void vkCmdPipelineBarrier(
        VkCommandBuffer                             commandBuffer,
        VkPipelineStageFlags                        srcStageMask,
        VkPipelineStageFlags                        dstStageMask,
        VkDependencyFlags                           dependencyFlags,
        u32                                         memoryBarrierCount,
        const VkMemoryBarrier*                      pMemoryBarriers,
        u32                                         bufferMemoryBarrierCount,
        const VkBufferMemoryBarrier*                pBufferMemoryBarriers,
        u32                                         imageMemoryBarrierCount,
        const VkImageMemoryBarrier*                 pImageMemoryBarriers) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    memoryBarriers := pMemoryBarriers[0:memoryBarrierCount]
    for i in (0 .. memoryBarrierCount) {
        memoryBarrier := memoryBarriers[i]
    }
    bufferMemoryBarriers := pBufferMemoryBarriers[0:bufferMemoryBarrierCount]
    for i in (0 .. bufferMemoryBarrierCount) {
        bufferMemoryBarrier := bufferMemoryBarriers[i]
        bufferObject := GetBuffer(bufferMemoryBarrier.buffer)
        assert(bufferObject.device == commandBufferObject.device)
    }
    imageMemoryBarriers := pImageMemoryBarriers[0:imageMemoryBarrierCount]
    for i in (0 .. imageMemoryBarrierCount) {
        imageMemoryBarrier := imageMemoryBarriers[i]
        imageObject := GetImage(imageMemoryBarrier.image)
        assert(imageObject.device == commandBufferObject.device)
    }
}

@threadSafety("app")
cmd void vkCmdBeginQuery(
        VkCommandBuffer                             commandBuffer,
        VkQueryPool                                 queryPool,
        u32                                         query,
        VkQueryControlFlags                         flags) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    queryPoolObject := GetQueryPool(queryPool)
    assert(commandBufferObject.device == queryPoolObject.device)
}

@threadSafety("app")
cmd void vkCmdEndQuery(
        VkCommandBuffer                             commandBuffer,
        VkQueryPool                                 queryPool,
        u32                                         query) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    queryPoolObject := GetQueryPool(queryPool)
    assert(commandBufferObject.device == queryPoolObject.device)
}

@threadSafety("app")
cmd void vkCmdResetQueryPool(
        VkCommandBuffer                             commandBuffer,
        VkQueryPool                                 queryPool,
        u32                                         firstQuery,
        u32                                         queryCount) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    queryPoolObject := GetQueryPool(queryPool)
    assert(commandBufferObject.device == queryPoolObject.device)
}

@threadSafety("app")
cmd void vkCmdWriteTimestamp(
        VkCommandBuffer                             commandBuffer,
        VkPipelineStageFlagBits                     pipelineStage,
        VkQueryPool                                 queryPool,
        u32                                         query) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    queryPoolObject := GetQueryPool(queryPool)
    assert(commandBufferObject.device == queryPoolObject.device)
}

@threadSafety("app")
cmd void vkCmdCopyQueryPoolResults(
        VkCommandBuffer                             commandBuffer,
        VkQueryPool                                 queryPool,
        u32                                         firstQuery,
        u32                                         queryCount,
        VkBuffer                                    dstBuffer,
        VkDeviceSize                                dstOffset,
        VkDeviceSize                                stride,
        VkQueryResultFlags                          flags) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    queryPoolObject := GetQueryPool(queryPool)
    dstBufferObject := GetBuffer(dstBuffer)
    assert(commandBufferObject.device == queryPoolObject.device)
    assert(commandBufferObject.device == dstBufferObject.device)
}

cmd void vkCmdPushConstants(
        VkCommandBuffer                             commandBuffer,
        VkPipelineLayout                            layout,
        VkShaderStageFlags                          stageFlags,
        u32                                         offset,
        u32                                         size,
        const void*                                 pValues) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    layoutObject := GetPipelineLayout(layout)
    assert(commandBufferObject.device == layoutObject.device)
}

@threadSafety("app")
cmd void vkCmdBeginRenderPass(
        VkCommandBuffer                             commandBuffer,
        const VkRenderPassBeginInfo*                pRenderPassBegin,
        VkSubpassContents                           contents) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
    renderPassObject := GetRenderPass(pRenderPassBegin.renderPass)
    framebufferObject := GetFramebuffer(pRenderPassBegin.framebuffer)
    assert(commandBufferObject.device == renderPassObject.device)
    assert(commandBufferObject.device == framebufferObject.device)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

cmd void vkCmdNextSubpass(
        VkCommandBuffer                             commandBuffer,
        VkSubpassContents                           contents) {
    commandBufferObject := GetCommandBuffer(commandBuffer)
}

@threadSafety("app")
cmd void vkCmdEndRenderPass(
        VkCommandBuffer                             commandBuffer) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    commandBufferObject.queueFlags = AddQueueFlag(commandBufferObject.queueFlags, VK_QUEUE_GRAPHICS_BIT)
}

cmd void vkCmdExecuteCommands(
        VkCommandBuffer                             commandBuffer,
        u32                                         commandBufferCount,
        const VkCommandBuffer*                      pCommandBuffers) {
    commandBufferObject := GetCommandBuffer(commandBuffer)

    commandBuffers := pCommandBuffers[0:commandBufferCount]
    for i in (0 .. commandBufferCount) {
        secondaryCommandBuffer := commandBuffers[i]
        secondaryCommandBufferObject := GetCommandBuffer(secondaryCommandBuffer)
        assert(commandBufferObject.device == secondaryCommandBufferObject.device)
    }
}

@extension("VK_KHR_surface")
cmd void vkDestroySurfaceKHR(
        VkInstance                                  instance,
        VkSurfaceKHR                                surface,
        const VkAllocationCallbacks*                pAllocator) {
    instanceObject := GetInstance(instance)
    surfaceObject := GetSurface(surface)
    assert(surfaceObject.instance == instance)

    State.Surfaces[surface] = null
}

@extension("VK_KHR_surface")
cmd VkResult vkGetPhysicalDeviceSurfaceSupportKHR(
        VkPhysicalDevice                            physicalDevice,
        u32                                         queueFamilyIndex,
        VkSurfaceKHR                                surface,
        VkBool32*                                   pSupported) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    return ?
}

@extension("VK_KHR_surface")
cmd VkResult vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
        VkPhysicalDevice                            physicalDevice,
        VkSurfaceKHR                                surface,
        VkSurfaceCapabilitiesKHR*                   pSurfaceCapabilities) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    surfaceCapabilities := ?
    pSurfaceCapabilities[0] = surfaceCapabilities

    return ?
}

@extension("VK_KHR_surface")
cmd VkResult vkGetPhysicalDeviceSurfaceFormatsKHR(
        VkPhysicalDevice                            physicalDevice,
        VkSurfaceKHR                                surface,
        u32*                                        pSurfaceFormatCount,
        VkSurfaceFormatKHR*                         pSurfaceFormats) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    count := as!u32(?)
    pSurfaceFormatCount[0] = count
    surfaceFormats := pSurfaceFormats[0:count]

    for i in (0 .. count) {
        surfaceFormat := ?
        surfaceFormats[i] = surfaceFormat
    }

    return ?
}

@extension("VK_KHR_surface")
cmd VkResult vkGetPhysicalDeviceSurfacePresentModesKHR(
        VkPhysicalDevice                            physicalDevice,
        VkSurfaceKHR                                surface,
        u32*                                        pPresentModeCount,
        VkPresentModeKHR*                           pPresentModes) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)

    count := as!u32(?)
    pPresentModeCount[0] = count
    presentModes := pPresentModes[0:count]

    for i in (0 .. count) {
        presentMode := ?
        presentModes[i] = presentMode
    }

    return ?
}

@extension("VK_KHR_swapchain")
cmd VkResult vkCreateSwapchainKHR(
        VkDevice                                 device,
        const VkSwapchainCreateInfoKHR*          pCreateInfo,
        const VkAllocationCallbacks*             pAllocator,
        VkSwapchainKHR*                          pSwapchain) {
    assert(pCreateInfo.sType == VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR)
    deviceObject := GetDevice(device)

    swapchain := ?
    pSwapchain[0] = swapchain
    State.Swapchains[swapchain] = new!SwapchainObject(device: device)

    return ?
}

@extension("VK_KHR_swapchain")
cmd void vkDestroySwapchainKHR(
        VkDevice                                 device,
        VkSwapchainKHR                           swapchain,
        const VkAllocationCallbacks*             pAllocator) {
    deviceObject := GetDevice(device)
    swapchainObject := GetSwapchain(swapchain)
    assert(swapchainObject.device == device)

    State.Swapchains[swapchain] = null
}

@extension("VK_KHR_swapchain")
cmd VkResult vkGetSwapchainImagesKHR(
        VkDevice                                 device,
        VkSwapchainKHR                           swapchain,
        u32*                                     pSwapchainImageCount,
        VkImage*                                 pSwapchainImages) {
    deviceObject := GetDevice(device)

    count := as!u32(?)
    pSwapchainImageCount[0] = count
    swapchainImages := pSwapchainImages[0:count]

    for i in (0 .. count) {
        swapchainImage := ?
        swapchainImages[i] = swapchainImage
        State.Images[swapchainImage] = new!ImageObject(device: device)
    }

    return ?
}

@extension("VK_KHR_swapchain")
cmd VkResult vkAcquireNextImageKHR(
        VkDevice                                 device,
        VkSwapchainKHR                           swapchain,
        u64                                      timeout,
        VkSemaphore                              semaphore,
        VkFence                                  fence,
        u32*                                     pImageIndex) {
    deviceObject := GetDevice(device)
    swapchainObject := GetSwapchain(swapchain)

    imageIndex := ?
    pImageIndex[0] = imageIndex

    return ?
}

@extension("VK_KHR_swapchain")
cmd VkResult vkQueuePresentKHR(
        VkQueue                                  queue,
        const VkPresentInfoKHR*                  pPresentInfo) {
    queueObject := GetQueue(queue)

    presentInfo := ?
    pPresentInfo[0] = presentInfo

    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkGetPhysicalDeviceDisplayPropertiesKHR(
        VkPhysicalDevice                        physicalDevice,
        u32*                                    pPropertyCount,
        VkDisplayPropertiesKHR*                 pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkGetPhysicalDeviceDisplayPlanePropertiesKHR(
        VkPhysicalDevice                        physicalDevice,
        u32*                                    pPropertyCount,
        VkDisplayPlanePropertiesKHR*            pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkGetDisplayPlaneSupportedDisplaysKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     planeIndex,
        u32*                                    pDisplayCount,
        VkDisplayKHR*                           pDisplays) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkGetDisplayModePropertiesKHR(
        VkPhysicalDevice                        physicalDevice,
        VkDisplayKHR                            display,
        u32*                                    pPropertyCount,
        VkDisplayModePropertiesKHR*             pProperties) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkCreateDisplayModeKHR(
        VkPhysicalDevice                        physicalDevice,
        VkDisplayKHR                            display,
        const VkDisplayModeCreateInfoKHR*       pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkDisplayModeKHR*                       pMode) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkGetDisplayPlaneCapabilitiesKHR(
        VkPhysicalDevice                        physicalDevice,
        VkDisplayModeKHR                        mode,
        u32                                     planeIndex,
        VkDisplayPlaneCapabilitiesKHR*          pCapabilities) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_display")
cmd VkResult vkCreateDisplayPlaneSurfaceKHR(
        VkInstance                              instance,
        const VkDisplaySurfaceCreateInfoKHR*    pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    return ?
}

@extension("VK_KHR_display_swapchain")
cmd VkResult vkCreateSharedSwapchainsKHR(
        VkDevice                                device,
        u32                                     swapchainCount,
        const VkSwapchainCreateInfoKHR*         pCreateInfos,
        const VkAllocationCallbacks*            pAllocator,
        VkSwapchainKHR*                         pSwapchains) {
    return ?
}

@extension("VK_KHR_xlib_surface")
cmd VkResult vkCreateXlibSurfaceKHR(
        VkInstance                              instance,
        const VkXlibSurfaceCreateInfoKHR*       pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_xlib_surface")
cmd VkBool32 vkGetPhysicalDeviceXlibPresentationSupportKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     queueFamilyIndex,
        platform.Display*                       dpy,
        platform.VisualID                       visualID) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_xcb_surface")
cmd VkResult vkCreateXcbSurfaceKHR(
        VkInstance                              instance,
        const VkXcbSurfaceCreateInfoKHR*        pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_xcb_surface")
cmd VkBool32 vkGetPhysicalDeviceXcbPresentationSupportKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     queueFamilyIndex,
        platform.xcb_connection_t*              connection,
        platform.xcb_visualid_t                 visual_id) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_wayland_surface")
cmd VkResult vkCreateWaylandSurfaceKHR(
        VkInstance                              instance,
        const VkWaylandSurfaceCreateInfoKHR*    pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_wayland_surface")
cmd VkBool32 vkGetPhysicalDeviceWaylandPresentationSupportKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     queueFamilyIndex,
        platform.wl_display*                    display) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_mir_surface")
cmd VkResult vkCreateMirSurfaceKHR(
        VkInstance                              instance,
        const VkMirSurfaceCreateInfoKHR*        pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_mir_surface")
cmd VkBool32 vkGetPhysicalDeviceMirPresentationSupportKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     queueFamilyIndex,
        platform.MirConnection*                 connection) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_KHR_android_surface")
cmd VkResult vkCreateAndroidSurfaceKHR(
        VkInstance                              instance,
        const VkAndroidSurfaceCreateInfoKHR*    pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_win32_surface")
cmd VkResult vkCreateWin32SurfaceKHR(
        VkInstance                              instance,
        const VkWin32SurfaceCreateInfoKHR*      pCreateInfo,
        const VkAllocationCallbacks*            pAllocator,
        VkSurfaceKHR*                           pSurface) {
    instanceObject := GetInstance(instance)
    return ?
}

@extension("VK_KHR_win32_surface")
cmd VkResult vkGetPhysicalDeviceWin32PresentationSupportKHR(
        VkPhysicalDevice                        physicalDevice,
        u32                                     queueFamilyIndex) {
    physicalDeviceObject := GetPhysicalDevice(physicalDevice)
    return ?
}

@extension("VK_ANDROID_native_buffer")
cmd VkResult vkGetSwapchainGrallocUsageANDROID(
        VkDevice                                device,
        VkFormat                                format,
        VkImageUsageFlags                       imageUsage,
        int*                                    grallocUsage) {
    return ?
}

@extension("VK_ANDROID_native_buffer")
cmd VkResult vkAcquireImageANDROID(
        VkDevice                                device,
        VkImage                                 image,
        int                                     nativeFenceFd,
        VkSemaphore                             semaphore,
        VkFence                                 fence) {
    return ?
}

@extension("VK_ANDROID_native_buffer")
cmd VkResult vkQueueSignalReleaseImageANDROID(
        VkQueue                                 queue,
        u32                                     waitSemaphoreCount,
        const VkSemaphore*                      pWaitSemaphores,
        VkImage                                 image,
        int*                                    pNativeFenceFd) {
    return ?
}

@extension("VK_EXT_debug_report")
@external type void* PFN_vkDebugReportCallbackEXT
@extension("VK_EXT_debug_report")
@pfn cmd VkBool32 vkDebugReportCallbackEXT(
        VkDebugReportFlagsEXT                   flags,
        VkDebugReportObjectTypeEXT              objectType,
        u64                                     object,
        platform.size_t                         location,
        s32                                     messageCode,
        const char*                             pLayerPrefix,
        const char*                             pMessage,
        void*                                   pUserData) {
    return ?
}

@extension("VK_EXT_debug_report")
cmd VkResult vkCreateDebugReportCallbackEXT(
        VkInstance                                  instance,
        const VkDebugReportCallbackCreateInfoEXT*   pCreateInfo,
        const VkAllocationCallbacks*                pAllocator,
        VkDebugReportCallbackEXT*                   pCallback) {
    return ?
}

@extension("VK_EXT_debug_report")
cmd void vkDestroyDebugReportCallbackEXT(
        VkInstance                                  instance,
        VkDebugReportCallbackEXT                    callback,
        const VkAllocationCallbacks*                pAllocator) {
}

@extension("VK_EXT_debug_report")
cmd void vkDebugReportMessageEXT(
        VkInstance                                  instance,
        VkDebugReportFlagsEXT                       flags,
        VkDebugReportObjectTypeEXT                  objectType,
        u64                                         object,
        platform.size_t                             location,
        s32                                         messageCode,
        const char*                                 pLayerPrefix,
        const char*                                 pMessage) {
}

@extension("VK_EXT_debug_marker")
cmd VkResult vkDebugMarkerSetObjectTagEXT(
        VkDevice                                    device,
        VkDebugMarkerObjectTagInfoEXT*              pTagInfo) {
    return ?
}

@extension("VK_EXT_debug_marker")
cmd VkResult vkDebugMarkerSetObjectNameEXT(
        VkDevice                                    device,
        VkDebugMarkerObjectNameInfoEXT*             pNameInfo) {
    return ?
}

@extension("VK_EXT_debug_marker")
cmd void vkCmdDebugMarkerBeginEXT(
        VkCommandBuffer                             commandBuffer,
        VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo) {
}

@extension("VK_EXT_debug_marker")
cmd void vkCmdDebugMarkerEndEXT(
        VkCommandBuffer                             commandBuffer) {
}

@extension("VK_EXT_debug_marker")
cmd void vkCmdDebugMarkerInsertEXT(
        VkCommandBuffer                             commandBuffer,
        VkDebugMarkerMarkerInfoEXT*                 pMarkerInfo) {
}


////////////////
// Validation //
////////////////

extern void validate(string layerName, bool condition, string message)


/////////////////////////////
// Internal State Tracking //
/////////////////////////////

StateObject State

@internal class StateObject {
    // Dispatchable objects.
    map!(VkInstance,       ref!InstanceObject)       Instances
    map!(VkPhysicalDevice, ref!PhysicalDeviceObject) PhysicalDevices
    map!(VkDevice,         ref!DeviceObject)         Devices
    map!(VkQueue,          ref!QueueObject)          Queues
    map!(VkCommandBuffer,  ref!CommandBufferObject)  CommandBuffers

    // Non-dispatchable objects.
    map!(VkDeviceMemory,             ref!DeviceMemoryObject)             DeviceMemories
    map!(VkBuffer,                   ref!BufferObject)                   Buffers
    map!(VkBufferView,               ref!BufferViewObject)               BufferViews
    map!(VkImage,                    ref!ImageObject)                    Images
    map!(VkImageView,                ref!ImageViewObject)                ImageViews
    map!(VkShaderModule,             ref!ShaderModuleObject)             ShaderModules
    map!(VkPipeline,                 ref!PipelineObject)                 Pipelines
    map!(VkPipelineLayout,           ref!PipelineLayoutObject)           PipelineLayouts
    map!(VkSampler,                  ref!SamplerObject)                  Samplers
    map!(VkDescriptorSet,            ref!DescriptorSetObject)            DescriptorSets
    map!(VkDescriptorSetLayout,      ref!DescriptorSetLayoutObject)      DescriptorSetLayouts
    map!(VkDescriptorPool,           ref!DescriptorPoolObject)           DescriptorPools
    map!(VkFence,                    ref!FenceObject)                    Fences
    map!(VkSemaphore,                ref!SemaphoreObject)                Semaphores
    map!(VkEvent,                    ref!EventObject)                    Events
    map!(VkQueryPool,                ref!QueryPoolObject)                QueryPools
    map!(VkFramebuffer,              ref!FramebufferObject)              Framebuffers
    map!(VkRenderPass,               ref!RenderPassObject)               RenderPasses
    map!(VkPipelineCache,            ref!PipelineCacheObject)            PipelineCaches
    map!(VkCommandPool,              ref!CommandPoolObject)              CommandPools
    map!(VkSurfaceKHR,               ref!SurfaceObject)                  Surfaces
    map!(VkSwapchainKHR,             ref!SwapchainObject)                Swapchains
}

@internal class InstanceObject {
}

@internal class PhysicalDeviceObject {
    VkInstance instance
}

@internal class DeviceObject {
    VkPhysicalDevice physicalDevice
}

@internal class QueueObject {
    VkDevice      device
    VkQueueFlags  flags
}

@internal class CommandBufferObject {
    VkDevice                  device
    map!(u64, VkDeviceMemory) boundObjects
    VkQueueFlags              queueFlags
}

@internal class DeviceMemoryObject {
    VkDevice                                device
    VkDeviceSize                            allocationSize
    map!(u64, VkDeviceSize)                 boundObjects
    map!(VkCommandBuffer, VkCommandBuffer)  boundCommandBuffers
}

@internal class BufferObject {
    VkDevice              device
    VkDeviceMemory        memory
    VkDeviceSize          memoryOffset
}

@internal class BufferViewObject {
    VkDevice      device
    VkBuffer      buffer
}

@internal class ImageObject {
    VkDevice              device
    VkDeviceMemory        memory
    VkDeviceSize          memoryOffset
}

@internal class ImageViewObject {
    VkDevice      device
    VkImage       image
}

@internal class ShaderObject {
    VkDevice      device
}

@internal class ShaderModuleObject {
    VkDevice      device
}

@internal class PipelineObject {
    VkDevice      device
}

@internal class PipelineLayoutObject {
    VkDevice      device
}

@internal class SamplerObject {
    VkDevice      device
}

@internal class DescriptorSetObject {
    VkDevice      device
}

@internal class DescriptorSetLayoutObject {
    VkDevice      device
}

@internal class DescriptorPoolObject {
    VkDevice      device
}

@internal class FenceObject {
    VkDevice      device
    bool          signaled
}

@internal class SemaphoreObject {
    VkDevice      device
}

@internal class EventObject {
    VkDevice      device
}

@internal class QueryPoolObject {
    VkDevice      device
}

@internal class FramebufferObject {
    VkDevice      device
}

@internal class RenderPassObject {
    VkDevice      device
}

@internal class PipelineCacheObject {
    VkDevice      device
}

@internal class CommandPoolObject {
    VkDevice      device
}

@internal class SurfaceObject {
    VkInstance    instance
}

@internal class SwapchainObject {
    VkDevice      device
}

macro ref!InstanceObject GetInstance(VkInstance instance) {
    assert(instance in State.Instances)
    return State.Instances[instance]
}

macro ref!PhysicalDeviceObject GetPhysicalDevice(VkPhysicalDevice physicalDevice) {
    assert(physicalDevice in State.PhysicalDevices)
    return State.PhysicalDevices[physicalDevice]
}

macro ref!DeviceObject GetDevice(VkDevice device) {
    assert(device in State.Devices)
    return State.Devices[device]
}

macro ref!QueueObject GetQueue(VkQueue queue) {
    assert(queue in State.Queues)
    return State.Queues[queue]
}

macro ref!CommandBufferObject GetCommandBuffer(VkCommandBuffer commandBuffer) {
    assert(commandBuffer in State.CommandBuffers)
    return State.CommandBuffers[commandBuffer]
}

macro ref!DeviceMemoryObject GetDeviceMemory(VkDeviceMemory memory) {
    assert(memory in State.DeviceMemories)
    return State.DeviceMemories[memory]
}

macro ref!BufferObject GetBuffer(VkBuffer buffer) {
    assert(buffer in State.Buffers)
    return State.Buffers[buffer]
}

macro ref!BufferViewObject GetBufferView(VkBufferView bufferView) {
    assert(bufferView in State.BufferViews)
    return State.BufferViews[bufferView]
}

macro ref!ImageObject GetImage(VkImage image) {
    assert(image in State.Images)
    return State.Images[image]
}

macro ref!ImageViewObject GetImageView(VkImageView imageView) {
    assert(imageView in State.ImageViews)
    return State.ImageViews[imageView]
}

macro ref!ShaderModuleObject GetShaderModule(VkShaderModule shaderModule) {
    assert(shaderModule in State.ShaderModules)
    return State.ShaderModules[shaderModule]
}

macro ref!PipelineObject GetPipeline(VkPipeline pipeline) {
    assert(pipeline in State.Pipelines)
    return State.Pipelines[pipeline]
}

macro ref!PipelineLayoutObject GetPipelineLayout(VkPipelineLayout pipelineLayout) {
    assert(pipelineLayout in State.PipelineLayouts)
    return State.PipelineLayouts[pipelineLayout]
}

macro ref!SamplerObject GetSampler(VkSampler sampler) {
    assert(sampler in State.Samplers)
    return State.Samplers[sampler]
}

macro ref!DescriptorSetObject GetDescriptorSet(VkDescriptorSet descriptorSet) {
    assert(descriptorSet in State.DescriptorSets)
    return State.DescriptorSets[descriptorSet]
}

macro ref!DescriptorSetLayoutObject GetDescriptorSetLayout(VkDescriptorSetLayout descriptorSetLayout) {
    assert(descriptorSetLayout in State.DescriptorSetLayouts)
    return State.DescriptorSetLayouts[descriptorSetLayout]
}

macro ref!DescriptorPoolObject GetDescriptorPool(VkDescriptorPool descriptorPool) {
    assert(descriptorPool in State.DescriptorPools)
    return State.DescriptorPools[descriptorPool]
}

macro ref!FenceObject GetFence(VkFence fence) {
    assert(fence in State.Fences)
    return State.Fences[fence]
}

macro ref!SemaphoreObject GetSemaphore(VkSemaphore semaphore) {
    assert(semaphore in State.Semaphores)
    return State.Semaphores[semaphore]
}

macro ref!EventObject GetEvent(VkEvent event) {
    assert(event in State.Events)
    return State.Events[event]
}

macro ref!QueryPoolObject GetQueryPool(VkQueryPool queryPool) {
    assert(queryPool in State.QueryPools)
    return State.QueryPools[queryPool]
}

macro ref!FramebufferObject GetFramebuffer(VkFramebuffer framebuffer) {
    assert(framebuffer in State.Framebuffers)
    return State.Framebuffers[framebuffer]
}

macro ref!RenderPassObject GetRenderPass(VkRenderPass renderPass) {
    assert(renderPass in State.RenderPasses)
    return State.RenderPasses[renderPass]
}

macro ref!PipelineCacheObject GetPipelineCache(VkPipelineCache pipelineCache) {
    assert(pipelineCache in State.PipelineCaches)
    return State.PipelineCaches[pipelineCache]
}

macro ref!CommandPoolObject GetCommandPool(VkCommandPool commandPool) {
    assert(commandPool in State.CommandPools)
    return State.CommandPools[commandPool]
}

macro ref!SurfaceObject GetSurface(VkSurfaceKHR surface) {
    assert(surface in State.Surfaces)
    return State.Surfaces[surface]
}

macro ref!SwapchainObject GetSwapchain(VkSwapchainKHR swapchain) {
    assert(swapchain in State.Swapchains)
    return State.Swapchains[swapchain]
}

macro VkQueueFlags AddQueueFlag(VkQueueFlags flags, VkQueueFlagBits bit) {
    return as!VkQueueFlags(as!u32(flags) | as!u32(bit))
}
