【转载】Vulkan 1.2 知识串讲(1)—— INSTANCE & DEVICE & QUEUE

  • Post author:
  • Post category:其他


【转载】Vulkan 1.2 知识串讲(1)—— INSTANCE & DEVICE & QUEUE

文章转自

电子设备中的画家|王烁 于 2021 年 4 月 20 日发表——Vulkan 1.2 知识串讲(1)

在这里插入图片描述

PFN_vkVoidFunction vkGetInstanceProcAddr( VkInstance instance, const char* pName);

在CTS,该函数是用于获取

vkGetPhysicalDeviceProperties2KHR

等函数的函数handle,比如:

PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR = reinterpret_cast<.PFN_vkGetPhysicalDeviceProperties2KHR>(vkGetInstanceProcAddr(instance->get_handle(), "vkGetPhysicalDeviceProperties2KHR"));

PFN_vkVoidFunction vkGetDeviceProcAddr( VkDevice device, const char* pName);

在CTS,该函数是用于获取

vkCmdPushDescriptorSetKHR

等函数的函数handle,比如:

vkCmdPushDescriptorSetKHR = (PFN_vkCmdPushDescriptorSetKHR) vkGetDeviceProcAddr(get_device().get_handle(), "vkCmdPushDescriptorSetKHR");

VkResult vkCreateInstance( const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);

在CTS中的使用:

result = vkCreateInstance(&instance_info, nullptr, &handle);

Vulkan中没有global state,每个应用程序的所偶遇状态都存储在VkInstance中:

  1. 第一个输入参数为创建instance所用到到的信息:
typedef struct VkInstanceCreateInfo {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
	VkStructureType sType;
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL
	const void* pNext;
	//reserved for future,必须是0
	VkInstanceCreateFlags flags;
	//NULL,或者一个包含应用程序信息的结构体,用于告诉instance应用程序信息。
	//如果使用NULL,或者使用一个0版本的apiVersion,则相当于使用了VK_MAKE_API_VERSION(0,1,0,0) 的apiVersion
	const VkApplicationInfo* pApplicationInfo;
	//启用的global layer的数量
	uint32_t enabledLayerCount;
	//启用的global layer的名字,第一个是最靠近应用程序的layer,最后一个是最靠近驱动的layer
	const char* const* ppEnabledLayerNames;
	//启用的global extension的数量
	uint32_t enabledExtensionCount;
	//启用的extension的名字,这里包含了所有的extension
	const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
typedef struct VkApplicationInfo {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_APPLICATION_INFO
	VkStructureType sType;
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL
	const void* pNext;
	//NULL,或者应用程序名字
	const char* pApplicationName;
	//应用程序版本
	uint32_t applicationVersion;
	//NULL,或者创建该应用程序的引擎名字
	const char* pEngineName;
	//引擎版本
	uint32_t engineVersion;
	//应用程序所支持的Vulkan的最高版本。当使用vulkan1.0的时候,这里如果写超过1.0的数字,会出现 
	//VK_ERROR_INCOMPATIBLE_DRIVER 的错误,因此,在创建之前,需要通过 vkGetInstanceProcAddr 获取 
	//vkEnumerateInstanceVersion 的信息,如果 vkEnumerateInstanceVersion 为 NULL,则 为vulkan 1.0,否则 
	//vkEnumerateInstanceVersion 即为 Vulkan版本。而vulkan1.1及以上版本永远不会出现这个错误。需要注意的是:validation layer
	//会根据这个版本,来判断,如果使用了高版本的特性,则会报validation error。比如,如果instance支持1.1,3个physical devices
	//支持1.0、1.1、1.2,如果应用程序将该值设置为1.2。则应用程序中,instance和所有的physical devices都可以使用1.0,
	//instance和1.1和1.2的physical devices可以使用1.1,1.2的physical device可以使用1.2。如果应用程序设置为1.1,则应
	//用程序即使在支持1.2的physical deevice上,也无法使用1.2。这个版本影响了layer的使用。除非是0,否则必须大于等于VK_API_VERSION_1_0
	uint32_t apiVersion;
} VkApplicationInfo;
  1. 第二个输入参数,用于内存分配
typedef struct VkAllocationCallbacks {
	void* pUserData;
	PFN_vkAllocationFunction pfnAllocation;
	PFN_vkReallocationFunction pfnReallocation;
	PFN_vkFreeFunction pfnFree;
	PFN_vkInternalAllocationNotification pfnInternalAllocation;
	PFN_vkInternalFreeNotification pfnInternalFree;
} VkAllocationCallbacks;
  1. 第三个输入参数,用于获取生成的instance


vkCreateInstance

会验证 request layer是否存在,如果不存在,则返回

VK_ERROR_LAYER_NOT_PRESENT


vkCreateInstance

会验证 request extension是否支持(在当前instance或者所有开启的instance),如果有extension不支持,则返回

VK_ERROR_EXTENSION_NOT_PRESENT

如果有layer和extension必须同时存在,则在这里就需要同时存在。

可能会出现的错误:

VK_ERROR_OUT_OF_HOST_MEMORY



VK_ERROR_OUT_OF_DEVICE_MEMORY



VK_ERROR_INITIALIZATION_FAILED



VK_ERROR_LAYER_NOT_PRESENT



VK_ERROR_EXTENSION_NOT_PRESENT



VK_ERROR_INCOMPATIBLE_DRIVER

void vkDestroyInstance( VkInstance instance, const VkAllocationCallbacks* pAllocator);

在CTS中的使用:

vkDestroyInstance(handle, nullptr);



vkCreateInstance

对应,删除instance。删除instance之前,需要删除所有通过instance创建的物件。

第一个输入参数 可以是

NULL

,或者一个合法的

VkInstance

第二个输入参数如果不是

NULL

,则必须是一个合法的

VkAllocationCallbacks

结构体:如果

vkCreateInstance

的时候使用

VkAllocationCallbacks

了,那么删除的时候也需要提供一个与之兼容的

VkAllocationCallbacks

;如果

vkCreateInstance

的时候没有使用

VkAllocationCallbacks

,那么删除的时候

VkAllocationCallbacks

也必须是

NULL



Host access to instance must be externally synchronized





Host access to all VkPhysicalDevice objects enumerated from instance must be externally synchronized

VkResult vkEnumeratePhysicalDevices( VkInstance instance, uint32_t* pPhysicalDeviceCount, VkPhysicalDevice* pPhysicalDevices);

在CTS中的使用:

//获取physical devices的数量
vkEnumeratePhysicalDevices(context.instance, &gpu_count, nullptr);
//获取physical devices的list
vkEnumeratePhysicalDevices(context.instance, &gpu_count, gpus.data());

该API用于获取物理设备的信息(比如多个GPU的情况)

第一个输入参数为使用

vkCreateInstance

创建的 instance 。

第二个输入参数用于获取 avaliable或者queried的physical devices 的数量。

第三个输入参数可以是

NULL

,或者一个指向

VkPhysicalDevice

handle 数组的指针。

如果 pPhysicalDevices 为

NULL

,则可用的 physical devices 的数量通过 pPhysicalDeviceCount 返回。否则, pPhysicalDeviceCount 必须和 pPhysicalDevices 的元素数量匹配,执行完毕后, pPhysicalDeviceCount 将被赋值为真实获取到的 pPhysicalDevices的元素数量。假如 pPhysicalDeviceCount 小于可用的 physical devices 数量,那么最多可以获取到 pPhysicalDeviceCount 个physical devices,并且返回

VK_INCOMPLETE

(而非

VK_SUCCESS

,但是也算是成功了),说明并非所有可用的physical devices都被获取到了。

可能会出现的错误:

VK_ERROR_OUT_OF_HOST_MEMORY



VK_ERROR_OUT_OF_DEVICE_MEMORY



VK_ERROR_INITIALIZATION_FAILED

void vkGetPhysicalDeviceProperties( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties* pProperties);

在CTS中的使用:

vkGetPhysicalDeviceProperties(physical_device, &properties);

用于获取通过

vkEnumeratePhysicalDevices

得到的physical device的属性。

第一个输入参数为被查询的 physicalDevice。

第二个输入参数为一个指向

VkPhysicalDeviceProperties

的指针,用于获取被查询出来的数据:

typedef struct VkPhysicalDeviceProperties {
	//当前device支持的Vulkan版本,需要注意的是,这里的apiVersion可能会和 vkEnumerateInstanceVersion 获取到的不同,可能高或者低。
	//这种情况,应用程序不能使用超过given object相关的vulkan 版本的特性。
	//vkEnumerateInstanceVersion 返回的 pApiVersion ,为instance及其children相关的版本,
	//而非 VkPhysicalDevice 以及其 children。 
	//VkPhysicalDeviceProperties::apiVersion 为 VkPhysicalDevice 及其 children 相关的版本。
	uint32_t apiVersion;
	//vendor公司设定的驱动版本,driverVersion 的编码格式为 implementation-defined,可能与apiVersion的编码格式不同。
	//应用程序需要根据vendor提供的信息,来从driverVersion 获取版本信息
	uint32_t driverVersion;
	//当前physical device对应的vendor公司的标识
	uint32_t vendorID;
	//当前physical device的标识符
	uint32_t deviceID;
	//当前device的类型 
	VkPhysicalDeviceType deviceType;
	//一个包含 VK_MAX_PHYSICAL_DEVICE_NAME_SIZE 元素的数组,包含了physical device的name
	char deviceName[VK_MAX_PHYSICAL_DEVICE_NAME_SIZE];
	//一个包含 VK_UUID_SIZE 元素的数组,表示当前设备中的一个唯一标识符 
	uint8_t pipelineCacheUUID[VK_UUID_SIZE];
	//当前physical device的限制
	VkPhysicalDeviceLimits limits; 
	//当前physical device的various sparse 相关属性
	VkPhysicalDeviceSparseProperties sparseProperties; 
} VkPhysicalDeviceProperties;

physical device type不会影响操作。然而可能会与系统的其他公开属性或者功能相关,比如有多少内存。

typedef enum VkPhysicalDeviceType {
	VK_PHYSICAL_DEVICE_TYPE_OTHER = 0, //当前device不符合任何avaliable类型 
	VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU = 1, //当前device为嵌入式或者与主机密切耦合的设备 
	VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU = 2, //当前device为通过interlink与主机关联的独立处理器 
	VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU = 3, //当前device为虚拟机
	VK_PHYSICAL_DEVICE_TYPE_CPU = 4, //当前device运行在与主机相同的处理器上
} VkPhysicalDeviceType;
typedef struct VkPhysicalDeviceLimits {
    uint32_t              maxImageDimension1D;
    uint32_t              maxImageDimension2D;
    uint32_t              maxImageDimension3D;
    uint32_t              maxImageDimensionCube;
    uint32_t              maxImageArrayLayers;
    uint32_t              maxTexelBufferElements;
    uint32_t              maxUniformBufferRange;
    uint32_t              maxStorageBufferRange;
    uint32_t              maxPushConstantsSize;
    uint32_t              maxMemoryAllocationCount;
    uint32_t              maxSamplerAllocationCount;
    VkDeviceSize          bufferImageGranularity;
    VkDeviceSize          sparseAddressSpaceSize;
    uint32_t              maxBoundDescriptorSets;
    uint32_t              maxPerStageDescriptorSamplers;
    uint32_t              maxPerStageDescriptorUniformBuffers;
    uint32_t              maxPerStageDescriptorStorageBuffers;
    uint32_t              maxPerStageDescriptorSampledImages;
    uint32_t              maxPerStageDescriptorStorageImages;
    uint32_t              maxPerStageDescriptorInputAttachments;
    uint32_t              maxPerStageResources;
    uint32_t              maxDescriptorSetSamplers;
    uint32_t              maxDescriptorSetUniformBuffers;
    uint32_t              maxDescriptorSetUniformBuffersDynamic;
    uint32_t              maxDescriptorSetStorageBuffers;
    uint32_t              maxDescriptorSetStorageBuffersDynamic;
    uint32_t              maxDescriptorSetSampledImages;
    uint32_t              maxDescriptorSetStorageImages;
    uint32_t              maxDescriptorSetInputAttachments;
    uint32_t              maxVertexInputAttributes;
    uint32_t              maxVertexInputBindings;
    uint32_t              maxVertexInputAttributeOffset;
    uint32_t              maxVertexInputBindingStride;
    uint32_t              maxVertexOutputComponents;
    uint32_t              maxTessellationGenerationLevel;
    uint32_t              maxTessellationPatchSize;
    uint32_t              maxTessellationControlPerVertexInputComponents;
    uint32_t              maxTessellationControlPerVertexOutputComponents;
    uint32_t              maxTessellationControlPerPatchOutputComponents;
    uint32_t              maxTessellationControlTotalOutputComponents;
    uint32_t              maxTessellationEvaluationInputComponents;
    uint32_t              maxTessellationEvaluationOutputComponents;
    uint32_t              maxGeometryShaderInvocations;
    uint32_t              maxGeometryInputComponents;
    uint32_t              maxGeometryOutputComponents;
    uint32_t              maxGeometryOutputVertices;
    uint32_t              maxGeometryTotalOutputComponents;
    uint32_t              maxFragmentInputComponents;
    uint32_t              maxFragmentOutputAttachments;
    uint32_t              maxFragmentDualSrcAttachments;
    uint32_t              maxFragmentCombinedOutputResources;
    uint32_t              maxComputeSharedMemorySize;
    uint32_t              maxComputeWorkGroupCount[3];
    uint32_t              maxComputeWorkGroupInvocations;
    uint32_t              maxComputeWorkGroupSize[3];
    uint32_t              subPixelPrecisionBits;
    uint32_t              subTexelPrecisionBits;
    uint32_t              mipmapPrecisionBits;
    uint32_t              maxDrawIndexedIndexValue;
    uint32_t              maxDrawIndirectCount;
    float                 maxSamplerLodBias;
    float                 maxSamplerAnisotropy;
    uint32_t              maxViewports;
    uint32_t              maxViewportDimensions[2];
    float                 viewportBoundsRange[2];
    uint32_t              viewportSubPixelBits;
    size_t                minMemoryMapAlignment;
    VkDeviceSize          minTexelBufferOffsetAlignment;
    VkDeviceSize          minUniformBufferOffsetAlignment;
    VkDeviceSize          minStorageBufferOffsetAlignment;
    int32_t               minTexelOffset;
    uint32_t              maxTexelOffset;
    int32_t               minTexelGatherOffset;
    uint32_t              maxTexelGatherOffset;
    float                 minInterpolationOffset;
    float                 maxInterpolationOffset;
    uint32_t              subPixelInterpolationOffsetBits;
    uint32_t              maxFramebufferWidth;
    uint32_t              maxFramebufferHeight;
    uint32_t              maxFramebufferLayers;
    VkSampleCountFlags    framebufferColorSampleCounts;
    VkSampleCountFlags    framebufferDepthSampleCounts;
    VkSampleCountFlags    framebufferStencilSampleCounts;
    VkSampleCountFlags    framebufferNoAttachmentsSampleCounts;
    uint32_t              maxColorAttachments;
    VkSampleCountFlags    sampledImageColorSampleCounts;
    VkSampleCountFlags    sampledImageIntegerSampleCounts;
    VkSampleCountFlags    sampledImageDepthSampleCounts;
    VkSampleCountFlags    sampledImageStencilSampleCounts;
    VkSampleCountFlags    storageImageSampleCounts;
    uint32_t              maxSampleMaskWords;
    VkBool32              timestampComputeAndGraphics;
    float                 timestampPeriod;
    uint32_t              maxClipDistances;
    uint32_t              maxCullDistances;
    uint32_t              maxCombinedClipAndCullDistances;
    uint32_t              discreteQueuePriorities;
    float                 pointSizeRange[2];
    float                 lineWidthRange[2];
    float                 pointSizeGranularity;
    float                 lineWidthGranularity;
    VkBool32              strictLines;
    VkBool32              standardSampleLocations;
    VkDeviceSize          optimalBufferCopyOffsetAlignment;
    VkDeviceSize          optimalBufferCopyRowPitchAlignment;
    VkDeviceSize          nonCoherentAtomSize;
} VkPhysicalDeviceLimits;
typedef struct VkPhysicalDeviceSparseProperties {
    VkBool32    residencyStandard2DBlockShape;
    VkBool32    residencyStandard2DMultisampleBlockShape;
    VkBool32    residencyStandard3DBlockShape;
    VkBool32    residencyAlignedMipSize;
    VkBool32    residencyNonResidentStrict;
} VkPhysicalDeviceSparseProperties;
//vendorID 的枚举值,这个枚举随时可能更新,只有vk.xml和vulkan_core.h才包含了所有reserved Khronos vendor IDs。
//只有在Khronos注册的vendor IDs才会返回名字,根据 implementation 返回的PCI vendor IDs可以通过PCI-SIG database 进行查询。
typedef enum VkVendorId {
	VK_VENDOR_ID_VIV = 0x10001,
	VK_VENDOR_ID_VSI = 0x10002,
	VK_VENDOR_ID_KAZAN = 0x10003,
	VK_VENDOR_ID_CODEPLAY = 0x10004,
	VK_VENDOR_ID_MESA = 0x10005,
	VK_VENDOR_ID_POCL = 0x10006,
} VkVendorId;

void vkGetPhysicalDeviceProperties2( VkPhysicalDevice physicalDevice, VkPhysicalDeviceProperties2* pProperties);

在CTS中的使用:

vkGetPhysicalDeviceProperties2(get_device().get_gpu().get_handle(), &device_properties);

用于获取通过

vkEnumeratePhysicalDevices

得到的physical device的属性

第一个输入参数为被查询的 physicalDevice。

第二个输入参数为一个指向

VkPhysicalDeviceProperties2

的指针,用于获取被查询出来的数据

typedef struct VkPhysicalDeviceProperties2 {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2
	VkStructureType sType;
	//NULL,或者扩展该结构体的另外一个结构体(包含extension定义的属性),结构体的类型是:
	//VkPhysicalDeviceDepthStencilResolveProperties, VkPhysicalDeviceDescriptorIndexingProperties, 
	//VkPhysicalDeviceDriverProperties, VkPhysicalDeviceFloatControlsProperties, 
	//VkPhysicalDeviceIDProperties, VkPhysicalDeviceMaintenance3Properties, 
	//VkPhysicalDeviceMultiviewProperties, VkPhysicalDevicePointClippingProperties, 
	//VkPhysicalDeviceProtectedMemoryProperties, VkPhysicalDeviceSamplerFilterMinmaxProperties, 
	//VkPhysicalDeviceSubgroupProperties, VkPhysicalDeviceTimelineSemaphoreProperties, 
	//VkPhysicalDeviceVulkan11Properties, or VkPhysicalDeviceVulkan12Properties。
	//pNext中的 sType 必须 unique 
	void* pNext; 
	//一个指向 VkPhysicalDeviceProperties 的指针,用于获取被查询出来的数据,与 vkGetPhysicalDeviceProperties 相同。
	VkPhysicalDeviceProperties properties; 
} VkPhysicalDeviceProperties2;

void vkGetPhysicalDeviceQueueFamilyProperties( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties* pQueueFamilyProperties);

在CTS中的使用:

vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_properties_count, queue_family_properties.data());

用于获取通过

vkEnumeratePhysicalDevices

得到的physical device的 avaliable queues的属性。

第一个输入参数为被查询的 physicalDevice。

第二个输入参数用于获取 avaliable或者queried的queue families 的数量。

第三个输入参数可以是

NULL

,或者一个指向

VkQueueFamilyProperties

handle 数组的指针。

如果 pQueueFamilyProperties 为

NULL

,则可用的 queue families 的数量通过 pQueueFamilyPropertyCount 返回。Implementations 必须至少支持一个queue family。否则, pQueueFamilyPropertyCount 必须和 pQueueFamilyProperties 的元素数量匹配,执行完毕后, pQueueFamilyPropertyCount 将被赋值为真实获取到的 pQueueFamilyProperties 的元素数量。假如 pQueueFamilyPropertyCount 小于可用的 queue family 数量,那么最多可以获取到 pQueueFamilyPropertyCount 个queue family。

虽然我们期望一个physical device中所有相同能力的queue都存在一个family中。但是,尽管也应该这么实现,但依然有可能一个physical device中存在两个不同的queue family使用相同的能力。

typedef struct VkQueueFamilyProperties {
	//用于表示 VkQueueFlagBits , 是用于该queue family中queue的功能
	VkQueueFlags queueFlags;
	//为该queue family中 queue的数量。每个 queue family 至少包含一个 queue
	uint32_t queueCount; 
	//是通过 vkCmdWriteTimestamp 这个API输入的 timestamps 中有意义的位。该数值的有效位是36-64位(其他为应该为0),或者为0(代表不支持timestamps)
	uint32_t timestampValidBits; 
	//是该 queue family的queue中支持的image transfer 操作中的最小粒度,针对压缩纹理其单位为压缩的纹理block,否则为纹素。
	//可能的值为:(0,0,0):必须以整个mip level为单位进行transfer。这种情况下,有如下限制:1.VkOffset3D的参数x,y,z必须为0,2.VkExtent3D的参数width、height、depth必须匹配图片的w、h、d。
	//或者(Ax, Ay, Az),其中三个值均为POT。这种情况下,有如下限制:1.VkOffset3D的参数x,y,z必须为(Ax, Ay, Az)的整数倍,2.VkExtent3D的参数width、height、depth必须是(Ax, Ay, Az)的整数倍,或者x+width、y+height、z+depth等于图片尺寸。3.如果图片为压缩格式,则需要通过压缩texel block尺寸来放大粒度。
	VkExtent3D minImageTransferGranularity; 
} VkQueueFamilyProperties;
typedef enum VkQueueFlagBits {
	VK_QUEUE_GRAPHICS_BIT = 0x00000001, //说明这个queue支持graphics 操作 
	VK_QUEUE_COMPUTE_BIT = 0x00000002, //说明这个queue支持compute 操作 
	VK_QUEUE_TRANSFER_BIT = 0x00000004, //说明这个queue支持 transfer操作 
	VK_QUEUE_SPARSE_BINDING_BIT = 0x00000008, //说明这个queue支持 sparse memory management操作。如果开启了sparse resource feature,那么至少一个queue family支持这个bit // Provided by VK_VERSION_1_1 
	VK_QUEUE_PROTECTED_BIT = 0x00000010, //说明这个queue支持 VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT。如果physical device支持potectedMemory特性,则至少一个queue family支持这个bit
} VkQueueFlagBits;

graphics和compute queue必须支持 minImageTransferGranularity 为(1,1,1),这样的话,在这些queue的image transfer 操作中没有任何限制。其他queue只需要支持整张mip level的transfer,这样的话 minImageTransferGranularity 为(0,0,0)。

如果一个implementation 支持graphics操作的queue family,则至少一个physical device的一个queue family必须同时支持graphics和compute操作。

如果支持protected memory physical device,则至少一个physical device的一个queue family必须同时支持graphics和compute和rotected memory操作。

支持transfer操作的queue中的所有command,都被graphics/compute queue支持。所以,如果一个queue family支持

VK_QUEUE_GRAPHICS_BIT

/

VK_QUEUE_COMPUTE_BIT

,就相当于也同时开启了

VK_QUEUE_TRANSFER_BIT

void vkGetPhysicalDeviceQueueFamilyProperties2( VkPhysicalDevice physicalDevice, uint32_t* pQueueFamilyPropertyCount, VkQueueFamilyProperties2* pQueueFamilyProperties);

在CTS中的使用: 无

用于获取通过

vkEnumeratePhysicalDevices

得到的physical device的 avaliable queues的属性。

第一个输入参数为被查询的 physicalDevice。

第二个输入参数用于获取 avaliable或者queried的queue families 的数量。和

vkGetPhysicalDeviceQueueFamilyProperties

一样。

第三个输入参数可以是

NULL

,或者一个指向

VkQueueFamilyProperties2

handle 数组的指针。


vkGetPhysicalDeviceQueueFamilyProperties2



vkGetPhysicalDeviceQueueFamilyProperties

类似,除了会在pNext中多返回一个extended 信息

typedef struct VkQueueFamilyProperties2 {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_QUEUE_FAMILY_PROPERTIES_2
	VkStructureType sType; 
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL
	void* pNext; 
	//一个指向 VkQueueFamilyProperties 的指针,用于获取被查询出来的数据,与 vkGetPhysicalDeviceQueueFamilyProperties 相同。
	VkQueueFamilyProperties queueFamilyProperties; 
} VkQueueFamilyProperties2;

VkResult vkEnumeratePhysicalDeviceGroups( VkInstance instance, uint32_t* pPhysicalDeviceGroupCount, VkPhysicalDeviceGroupProperties* pPhysicalDeviceGroupProperties);

在CTS中的使用: 无

用于获取支持的device groups。

Device与physical device关联。每个device都会有一些queue family,每个queue family包含一个或者多个queue。一个queue family中的多个queue支持相同的操作。

一个Vulkan应用程序会先查询所有的physical devices,然后逐一的查询它们的属性(包含queue和queue family属性),一旦找到一个合适的physical device,该应用程序会创建一个device。该device将会成为该physical device的主要接口。

如果若干个physical devices属于同一个的device group,则可以将一个device与它们同时关联。一个device group的意思是若干个physical devices,互相可以访问内存,以及录制一个single command buffer,可以执行在所有的physical devices上。Device group是通过

vkEnumeratePhysicalDeviceGroups

查询,对应的device是通过device group中physical device的子集,将其传入

VkDeviceGroupDeviceCreateInfo

来创建。同一个device group中的两个physical devices,必须支持相同的extension、feature和属性,通过

vkGetPhysicalDevice*

获取的属性也基本相同(允许因为连接了不同的display、compositor等导致一些特定的query不同,这里就不列出来了)。

第一个输入参数为使用

vkCreateInstance

创建的 instance 。

第二个输入参数用于获取 avaliable或者queried的 device group 的数量。

第三个输入参数可以是

NULL

,或者一个指向

VkPhysicalDeviceGroupProperties

handle 数组的指针。

如果 pPhysicalDeviceGroupProperties 为

NULL

,则可用的 device group 的数量通过 pPhysicalDeviceGroupCount 返回。否则, pPhysicalDeviceGroupCount 必须和 pPhysicalDeviceGroupProperties 的元素数量匹配,执行完毕后, pPhysicalDeviceGroupCount 将被赋值为真实获取到的 pPhysicalDeviceGroupProperties 的元素数量。假如 pPhysicalDeviceGroupCount 小于可用的 device group 数量,那么最多可以获取到 pPhysicalDeviceGroupCount 个device group,并且返回

VK_INCOMPLETE

(而非

VK_SUCCESS

,但是也算是成功了),说明并非所有可用的 device group 都被获取到了。

每个physical device 都必须存在于一个device group中

可能会出现的错误:

VK_ERROR_OUT_OF_HOST_MEMORY



VK_ERROR_OUT_OF_DEVICE_MEMORY



VK_ERROR_INITIALIZATION_FAILED

typedef struct VkPhysicalDeviceGroupProperties {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GROUP_PROPERTIES
	VkStructureType sType; 
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL 
	void* pNext; 
	//当前device group中physical devices的数量 
	uint32_t physicalDeviceCount; 
	//一个包含 VK_MAX_DEVICE_GROUP_SIZE 个 VkPhysicalDevice 元素的数组,其中包含了当前device group中所有的physical devices,所以,前 physicalDeviceCount 个元素是合法的。 
	VkPhysicalDevice physicalDevices[VK_MAX_DEVICE_GROUP_SIZE]; 
	//指定根据group创建的device,所分配的device memory的方式,通过 VkMemoryAllocateFlagsInfo 的 deviceMask 设置。
	//如果为 VK_FALSE ,那么所有的device memory都可以被 group中的所有physical devices共享。
	//如果 physicalDeviceCount 为 1,那么 subsetAllocation 必须是 VK_FALSE 。
	VkBool32 subsetAllocation;  
} VkPhysicalDeviceGroupProperties;

VkResult vkCreateDevice( VkPhysicalDevice physicalDevice, const VkDeviceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkDevice* pDevice);

在CTS中的使用:

vkCreateDevice(context.gpu, &device_info, nullptr, &context.device) ;

用于创建关联physical device的logical device。

Device将被用于:1.创建queue,2.创建和跟踪各种各样的synchronization constructs,3.分配、释放、管理内存,4.创建和破坏 command buffer和command buffer pool,5.创建、破环和管理graphics state(pipeline、resource descriptor等)

第一个输入参数为通过

vkEnumeratePhysicalDevices

得到的其中一个physical device。

第二个输入参数是创建device所需要的信息。

第三个输入参数是用于内存分配,可以是

NULL

第四个输入参数是为了得到创建出来的device的handle。


vkCreateDevice

会确认 ppEnabledExtensionNames 和 pEnabledFeatures 是否支持。如果有extension不支持,则会返回

VK_ERROR_EXTENSION_NOT_PRESENT

的错误,如果有 feature不支持,则会返回

VK_ERROR_FEATURE_NOT_PRESENT

的错误。可以在创建device之前,通过

vkEnumerateDeviceExtensionProperties

查询支持的 extension,以及通过

vkGetPhysicalDeviceFeatures

查询支持的 feature。

验证了 extension和feaature后,device则被创建。

可以通过一个physical device创建多个logical devices。创建logical device可能会因为 device-specific 资源的缺失而失败。如果出现这种情况,则返回

VK_ERROR_TOO_MANY_OBJECTS

的错误。

可能会出现的错误:

VK_ERROR_OUT_OF_HOST_MEMORY



VK_ERROR_OUT_OF_DEVICE_MEMORY



VK_ERROR_INITIALIZATION_FAILED



VK_ERROR_EXTENSION_NOT_PRESENT



VK_ERROR_FEATURE_NOT_PRESENT



VK_ERROR_TOO_MANY_OBJECTS



VK_ERROR_DEVICE_LOST

typedef struct VkDeviceCreateInfo {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO
	VkStructureType sType;
	//NULL,或者扩展该结构体的另外一个结构体,如果其中包含 VkPhysicalDeviceFeatures2 结构体,那么 pEnabledFeatures 必须是NULL
	const void* pNext; 
	//reserved for future,必须为0
	VkDeviceCreateFlags flags; 
	//为 pQueueCreateInfos 数组的尺寸,必须大于0
	uint32_t queueCreateInfoCount; 
	//一个指向 queueCreateInfoCount 个 VkDeviceQueueCreateInfo 数组的指针,创建logical device的时候同步创建这些queues
	const VkDeviceQueueCreateInfo* pQueueCreateInfos; 
	uint32_t enabledLayerCount; //这个已经废弃
	const char* const* ppEnabledLayerNames; //这个已经废弃
	//当前device开启的extension数量
	uint32_t enabledExtensionCount; 
	//一个指向 enabledExtensionCount 个 extension name元素的数组,在创建device的时候这些extension需要被开启,这些extension所依赖的extension也必须放在这个list中
	const char* const* ppEnabledExtensionNames; 
	//NULL,或者一个指针指向 VkPhysicalDeviceFeatures 结构体,其中用bool值指出需要开启的feature。
	const VkPhysicalDeviceFeatures* pEnabledFeatures; 
} VkDeviceCreateInfo;

pNext中的每个sType都必须是独一无二的。

pNext 必须是

NULL

,或者

VkDeviceGroupDeviceCreateInfo

,

VkPhysicalDevice16BitStorageFeatures

,

VkPhysicalDevice8BitStorageFeatures

,

VkPhysicalDeviceBufferDeviceAddressFeatures

,

VkPhysicalDeviceDescriptorIndexingFeatures

,

VkPhysicalDeviceFeatures2

,

VkPhysicalDeviceHostQueryResetFeatures

,

VkPhysicalDeviceImagelessFramebufferFeatures

,

VkPhysicalDeviceMultiviewFeatures

,

VkPhysicalDeviceProtectedMemoryFeatures

,

VkPhysicalDeviceSamplerYcbcrConversionFeatures

,

VkPhysicalDeviceScalarBlockLayoutFeatures

,

VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures

,

VkPhysicalDeviceShaderAtomicInt64Features

,

VkPhysicalDeviceShaderDrawParametersFeatures

,

VkPhysicalDeviceShaderFloat16Int8Features

,

VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures

,

VkPhysicalDeviceTimelineSemaphoreFeatures

,

VkPhysicalDeviceUniformBufferStandardLayoutFeatures

,

VkPhysicalDeviceVariablePointersFeatures

,

VkPhysicalDeviceVulkan11Features

,

VkPhysicalDeviceVulkan12Features

, or

VkPhysicalDeviceVulkanMemoryModelFeatures

如果 pNext 包含

VkPhysicalDeviceVulkan11Features

,那么它必须不能包含:


VkPhysicalDevice16BitStorageFeatures

,

VkPhysicalDeviceMultiviewFeatures

,

VkPhysicalDeviceVariablePointersFeatures

,

VkPhysicalDeviceProtectedMemoryFeatures

,

VkPhysicalDeviceSamplerYcbcrConversionFeatures

, or

VkPhysicalDeviceShaderDrawParametersFeatures

如果 pNext 包含

VkPhysicalDeviceVulkan12Features

,那么它必须不能包含 :


VkPhysicalDevice8BitStorageFeatures

,

VkPhysicalDeviceShaderAtomicInt64Features

,

VkPhysicalDeviceShaderFloat16Int8Features

,

VkPhysicalDeviceDescriptorIndexingFeatures

,

VkPhysicalDeviceScalarBlockLayoutFeatures

,

VkPhysicalDeviceImagelessFramebufferFeatures

,

VkPhysicalDeviceUniformBufferStandardLayoutFeatures

,

VkPhysicalDeviceShaderSubgroupExtendedTypesFeatures

,

VkPhysicalDeviceSeparateDepthStencilLayoutsFeatures

,

VkPhysicalDeviceHostQueryResetFeatures

,

VkPhysicalDeviceTimelineSemaphoreFeatures

,

VkPhysicalDeviceBufferDeviceAddressFeatures

, or

VkPhysicalDeviceVulkanMemoryModelFeatures

一个logical device可以关联若干个physical devices,方法是在pNext中加入

VkDeviceGroupDeviceCreateInfo

结构体:

typedef struct VkDeviceGroupDeviceCreateInfo {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_DEVICE_GROUP_DEVICE_CREATE_INFO
	VkStructureType sType; 
	//NULL,或者扩展该结构体的另外一个结构体
	const void* pNext; 
	//pPhysicalDevices 数组的元素数量,如果这个数字不为0, vkCreateDevice 的 physicalDevice 参数必须是 pPhysicalDevices 中的一个元素
	uint32_t physicalDeviceCount; 
	//一个 physicalDeviceCount 个 physical device 的数组,其中的元素都属于同一个device group(从 vkEnumeratePhysicalDeviceGroups 获取)。
	//是logical device关联的一个有序list,必须是一个device group的子集,可以与被get出来的时候的顺序不同。
	//该顺序决定了每个physical device 的device index。
	//一些命令和结构体用于若干个physical device会用到device index或者通过device index组成的device mask。数组中的每个元素必须独一无二。
	const VkPhysicalDevice* pPhysicalDevices;
} VkDeviceGroupDeviceCreateInfo;

假如pNext中没有

VkDeviceGroupDeviceCreateInfo

,或者 physicalDeviceCount 为 0,就相当于 physicalDeviceCount 为1,pPhysicalDevices 指向 physicalDevice。这个时候,该physical device的device index为0。

typedef struct VkDeviceQueueCreateInfo {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO
	VkStructureType sType; 
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL
	const void* pNext; 
	//flag,用于表明queue的behavior,如果不支持protected memory,则一定不能设置 VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT,必须是 VkDeviceQueueCreateFlagBits 组合出来的,或者0
	VkDeviceQueueCreateFlags flags; 
	//设置该device创建的queue family的index。
	//每个 pQueueCreateInfos 中的该元素必须独一无二,除非一个是 protected-capable queue,另外一个不是 protected-capable queue,这样的话,这两个 pQueueCreateInfos 可以使用相同的queueFamilyIndex。 
	//这个index对应 vkGetPhysicalDeviceQueueFamilyProperties 得到的 pQueueFamilyProperties 数组中的index,一定要小于 vkGetPhysicalDeviceQueueFamilyProperties 返回的 pQueueFamilyPropertyCount
	uint32_t queueFamilyIndex; 
	//设置 在上述 queue family 中创建多少个 queue。必须大于0,必须小于或者等于 VkQueueFamilyProperties 的 queueCount (通过 vkGetPhysicalDeviceQueueFamilyProperties 获取到的)
	uint32_t queueCount; 
	//一个指向 queueCount 个元素的数组,其中包含的归一化float 值(范围为[0.0,1.0]),代表着每个 queue 的优先级。1.0最高,0.0最低。
	//在同一个device中,优先级高的queue可以被分配更多的processing time。
	//而针对相同优先级的queue,除非有显示的synchronization primitives,否则implementation不规定其调度先后顺序。
	//优先级高的queue可以饿死优先级低的queue(直到优先级高的queue没有更多command需要执行)。
	//一个logical device的queue无法通过优先级的关系饿死其它logical device的queue。
	//当然,也没有强制规定,要求高优先级的queue必须拥有更多的processing time或者更高的服务质量。
	const float* pQueuePriorities; 
} VkDeviceQueueCreateInfo;
typedef enum VkDeviceQueueCreateFlagBits {
	// Provided by VK_VERSION_1_1 
	//指定 device queue 是一个 protected-capable 的queue
	VK_DEVICE_QUEUE_CREATE_PROTECTED_BIT = 0x00000001, 
} VkDeviceQueueCreateFlagBits;
typedef struct VkPhysicalDeviceFeatures {
    VkBool32    robustBufferAccess;
    VkBool32    fullDrawIndexUint32;
    VkBool32    imageCubeArray;
    VkBool32    independentBlend;
    VkBool32    geometryShader;
    VkBool32    tessellationShader;
    VkBool32    sampleRateShading;
    VkBool32    dualSrcBlend;
    VkBool32    logicOp;
    VkBool32    multiDrawIndirect;
    VkBool32    drawIndirectFirstInstance;
    VkBool32    depthClamp;
    VkBool32    depthBiasClamp;
    VkBool32    fillModeNonSolid;
    VkBool32    depthBounds;
    VkBool32    wideLines;
    VkBool32    largePoints;
    VkBool32    alphaToOne;
    VkBool32    multiViewport;
    VkBool32    samplerAnisotropy;
    VkBool32    textureCompressionETC2;
    VkBool32    textureCompressionASTC_LDR;
    VkBool32    textureCompressionBC;
    VkBool32    occlusionQueryPrecise;
    VkBool32    pipelineStatisticsQuery;
    VkBool32    vertexPipelineStoresAndAtomics;
    VkBool32    fragmentStoresAndAtomics;
    VkBool32    shaderTessellationAndGeometryPointSize;
    VkBool32    shaderImageGatherExtended;
    VkBool32    shaderStorageImageExtendedFormats;
    VkBool32    shaderStorageImageMultisample;
    VkBool32    shaderStorageImageReadWithoutFormat;
    VkBool32    shaderStorageImageWriteWithoutFormat;
    VkBool32    shaderUniformBufferArrayDynamicIndexing;
    VkBool32    shaderSampledImageArrayDynamicIndexing;
    VkBool32    shaderStorageBufferArrayDynamicIndexing;
    VkBool32    shaderStorageImageArrayDynamicIndexing;
    VkBool32    shaderClipDistance;
    VkBool32    shaderCullDistance;
    VkBool32    shaderFloat64;
    VkBool32    shaderInt64;
    VkBool32    shaderInt16;
    VkBool32    shaderResourceResidency;
    VkBool32    shaderResourceMinLod;
    VkBool32    sparseBinding;
    VkBool32    sparseResidencyBuffer;
    VkBool32    sparseResidencyImage2D;
    VkBool32    sparseResidencyImage3D;
    VkBool32    sparseResidency2Samples;
    VkBool32    sparseResidency4Samples;
    VkBool32    sparseResidency8Samples;
    VkBool32    sparseResidency16Samples;
    VkBool32    sparseResidencyAliased;
    VkBool32    variableMultisampleRate;
    VkBool32    inheritedQueries;
} VkPhysicalDeviceFeatures;
typedef struct VkPhysicalDeviceFeatures2 {
    VkStructureType             sType;
    void*                       pNext;
    VkPhysicalDeviceFeatures    features;
} VkPhysicalDeviceFeatures2;

logical device可能会由于很多原因 lost,导致 pending和future的command execution可能会失败,导致resource和backing memory变成undefined。

典型的device loss的原因包括:执行超时(防止拒绝服务)、电源管理、平台资源管理、实现错误。

不遵守有效用法的应用程序也可能导致devie loss。即使device loss被reported,系统依然可能是一个无法恢复的状态,future的api依然invalid。

在这种情况下,某些命令将返回

VK_ERROR_DEVICE_LOST

,logical device会被认为是丢失状态,且无法重置为非丢失状态。然而丢失状态是特定于logical device的,对相应的physical device的其它方面可能没有影响。

在某些情况下,physical device也可能会丢失,尝试创建新的logical device会失败,返回

VK_ERROR_DEVICE_LOST

。这通常表示底层实现或其与主机的链接出现了问题。如果physical device没问题,那么通过它创建的新的logical device,也一定是处于非丢失状态。

虽然logical device丢失肯恶搞可以回复,但在physical device丢失的情况下,应用程序不太可能回复,除非系统上存在其他未受影响的physical device。该错误主要是用于通知用户发生了平台问题,应该进一步调查。比如,底层硬件可能出现了故障或者与其他其他物理断开了链接。在许多情况下,physical device丢失会导致其他更严重的问题,比如操作系统崩溃等,在这种情况下,可能不会通过Vulkan API报告。

当device丢失的时候,它的子对象不会被隐式销毁,并且它们的句柄依然有效。在销毁这些对象的父对象或者device之前,需要先销毁这些对象。使用

vkMapMemory

映射的设备内存,对应的主机地址空间仍然有效,对这些映射区域的主机内存访问依然有效,但内容未定义。在设备和子对象调用任何API命令仍然是合法的。

一旦device丢失,执行命令可能失败,返回

VK_ERROR_DEVICE_LOST

。一些命令不允许runtime error,仍然会正确运行,返回有效结果。

无限期等待device执行的命令(

vkDeviceWaitIdle



vkQueueWaitIdle



vkWaitForFences

使用最大timeout值,

vkGetQueryPoolResults

的flag设置为

VK_QUERY_RESULT_WAIT_BIT

)必须在有限时间内返回,即使设备丢失,也必须返回

VK_SUCCESS

或者

VK_ERROR_DEVICE_LOST

。对于可能返回

VK_ERROR_DEVICE_LOST

的命令,为了确定command buffer是否处于pending 状态,或者resource被认为是被device使用中,

VK_ERROR_DEVICE_LOST

的返回值等同于

VK_SUCCESS

从丢失的device导入或者到处的任何外部内存对象的内容都将变得未定义。与丢失devcie的外部内存对象相关联的,其他logica device或者通过其他API中的对象不会收到影响,只是它们的内容变得未定义。绑定到与丢失device上的外部内存对象相关联的VkDeviceMemory对象的其他logical device上影响的子资源的布局将变为

VK_IMAGE_LAYOUT_UNDEFINED

其他logical device上,通过semaphore payload 与丢失的device 关联的

VkSemaphore

对象,也是未定义。实现必须确保这些信号量上的挂起和随后提交的等待操作的行为符合wait操作的有效状态的外部信号量的等待操作的信号量状态要求中的定义。

void vkDestroyDevice( VkDevice device, const VkAllocationCallbacks* pAllocator);

在CTS中的使用:

vkDestroyDevice(context.device, nullptr); 

第一个输入参数是

vkCreateDevice

创建出来的device的handle。

第二个输入参数是用于内存分配,可以是

NULL

,如果

vkCreateDevice

的时候设置了该参数,这里也需要设置一个对应的 callback 参数。反之,如果

vkCreateDevice

的时候没有设置,那么这里必须是

NULL

为了确保device上没有活动的工作,可以使用

vkDeviceWaitIdle

来确保。在销毁 device之前,应用程序负责销毁/释放 device 通过

vkCreate*

或者

vkAllocate*

这些API 创建的Vulkan对象。

每个物件的生命周期都与

VkDevice

对象相关联。所以,为了避免资源泄露,应用程序必须在调用

vkDestroyDevice

之前显示释放所有这些资源。

queue是通过

vkCreateDevice

创建的,而一个logical device关联的所有queue,都是通过对这个device调用

vkDestroyDevice

被销毁的。



Host access to device must be externally synchronized

Host access to all VkQueue objects received from device must be externally synchronized

void vkGetDeviceQueue( VkDevice device, uint32_t queueFamilyIndex, uint32_t queueIndex, VkQueue* pQueue);

在CTS中的使用:

vkGetDeviceQueue(context.device, context.graphics_queue_index, 0, &context.queue);

获取 logical device中某个queue的handle。

第一个输入参数是拥有 queue 的logical device。

第二个输入参数是 queue 所在的 queue family 的 index,必须是创建logical device的时候,包含在

VkDeviceQueueCreateInfo

中的queue family index。

第三个输入参数是 queue 在 queue family 中的 index,必须小于创建logical device的时候,包含在

VkDeviceQueueCreateInfo

中的 queueCount。

第四个输入参数是获取到的 queue 的handle。


vkGetDeviceQueue

只能获取

VkDeviceQueueCreateInfo

的flag为0的queue,如果想获取flag不为0的queue,需要用

vkGetDeviceQueue2

正如上述所言,

vkGetPhysicalDeviceQueueFamilyProperties

可以获取到 physical device 支持的queue family和queue。

vkGetPhysicalDeviceQueueFamilyProperties

获取到的 pQueueFamilyProperties 中的 index 都是独一无二的,这些index被用于创建 queue,与

vkCreateDevice

中的

VkDeviceQueueCreateInfo

中的 queueFamilyIndex 相对应。

queue family index在很多地方会使用到,除了这里之外,还有,在创建

VkCommandPool

的时候,需要在

VkCommandPoolCreateInfo

中设置一个 queue family index。 这个Pool中的Command buffer 只能 submit到该 queue family 中的queue中。

在创建

VkImage



VkBuffer

的时候,也需要通过

VkImageCreateInfo



VkBufferCreateInfo

指定 queue families,指定只有这些 queue familyies可以访问这些资源。

当插入一个

VkBufferMemoryBarrier

或者

VkImageMemoryBarrier

的时候,需要设置一个source和一个desination queue family来指定,将buffer或者image的ownership从一个queue family转移到另外一个queue family。

void vkGetDeviceQueue2( VkDevice device, const VkDeviceQueueInfo2* pQueueInfo, VkQueue* pQueue);

在CTS中的使用:无

获取 logical device中在

VkDeviceQueueCreateFlags

中设定了特殊 flag 的 queue 的handle。

第一个输入参数是拥有 queue 的logical device。

第二个输入参数是一个

VkDeviceQueueInfo2

类型的结构体,包含了 queue 的参数。

第三个输入参数是获取到的 queue 的handle 。

typedef struct VkDeviceQueueInfo2 {
	//当前结构体的类型,必须是 VK_STRUCTURE_TYPE_DEVICE_QUEUE_INFO_2
	VkStructureType sType; 
	//NULL,或者扩展该结构体的另外一个结构体,必须是NULL
	const void* pNext; 
	//是创建该queue时候的 VkDeviceQueueCreateFlags flag,必须是 VkDeviceQueueCreateFlagBits 的合法组合。
	//如果在创建device的时候,没有创建对应flag的queue,则返回NULL
	VkDeviceQueueCreateFlags flags; 
	//queue 所在的 queue family 的 index,必须是创建logical device的时候,包含在 VkDeviceQueueCreateInfo 中的queue family index
	uint32_t queueFamilyIndex; 
	//queue 在 queue family 中的 index,必须小于创建logical device的时候,包含在 VkDeviceQueueCreateInfo 中的 queueCount
	uint32_t queueIndex; 
} VkDeviceQueueInfo2;

所有工作都是通过

vkQueueSubmit

被submit到一个queue中的。被submit到queue中的command包含一些列针对physical device的操作,比如 synchronization with semaphores and fences。

该submit command的参数中包含一个目标queue,0个或者batches work,一个可选的fence来标志完成。每个batch都包含三个方面内容:

1.在执行batch剩下内容之前,等待0个或者多个semaphores。

2. 0个或者多个work item需要执行。

3. 3.0个或者多个semaphores来标志该work item是否完成。

如果queue submission中含一个fense,则表示一个fence signal operation。

一个queue submission包含的所有work,都必须在command返回之前,submit 到queue。

在Vulkan中,支持将buffer、image与memory sparase bind。sparase memory binding是一个queue操作,一个包含

VK_QUEUE_SPARSE_BINDING_BIT

的 queue必须支持将device上的一个virtual address和一个physical address映射。这会导致device上page table的一次更新。这个更新必须与queue同步,以避免graphics command在执行过程中page table被破坏。由于需要在queue上bind sparse memory,那么所有依赖被更新的binding 同步的command都需要在binding更新后执行。后面的章节会介绍如何完成这个同步。

本节教程就到此结束,希望大家继续阅读我之后的教程。

谢谢大家,再见!