原文链接:https://vulkan.lunarg.com/doc/view/1.2.135.0/windows/chunked_spec/chap3.html#initialization
更新记录:
2020/4/22 增加 3 初始化、增加 3.1 函数指针、增加 3.2 实例(未完)、增加(额外章节) 3.2.1 Vulkan版本
2020/4/22 补上3.1.1扩展物理设备核心功能,补上3.1.2 通过设备扩展扩展物理设备
2020/4/22 增加3.2实例(到VkValidationFlagsEXT小段之前(包括VkValidationFlagsEXT)翻译完成,接下来是VkValidationFeaturesEXT)
2020/4/23 第3章初始化 翻译完成
ლ(´ڡ`ლ) (*≧m≦*) (*・ω・) ヾ(。・ω・。) (=゚ω゚)ノ (○’ω’○) (´?ω?`) (。-`ω´-) (。⌒∇⌒)。
至此Vulkan官方文档第三章翻译完成,请大家如果发现问题及时留言。谢谢!
ლ(´ڡ`ლ) (*≧m≦*) (*・ω・) ヾ(。・ω・。) (=゚ω゚)ノ (○’ω’○) (´?ω?`) (。-`ω´-) (。⌒∇⌒)。
3 初始化
在使用Vulkan之前,必须创建一个VkInstance对象用于初始化Vulkan和加载Vulkan函数。
3.1函数指针
Vulkan的函数并不一定是通过静态链接暴露出来的,有时通过调用Vulkan提供的查询函数来获取Vulkan函数指针(特别是获取某些扩展提供的扩展函数)。
注::
某些扩展在未来的Vulkan中可能会从扩展标准荣升到核心标准中,或是被合并到其他扩展中。这时这些扩展中的函数一般都会有一个别名函数(可理解成typedef)。调用函数和调用其别名函数结果是一样的,但是获取每一个别名函数的行为是不一样的。在获取之前需要查看是否支持该扩展,并且查看该扩展是否支持该别名函数。
可通过调用vkGetInstanceProcAddr函数来获取Vulkan中的所有函数指针。
PFN_vkVoidFunction定义如下
typedef void (VKAPI_PTR *PFN_vkVoidFunction)(void);
PFN_vkVoidFunction vkGetInstanceProcAddr(
VkInstance instance,
const char* pName
);
- instance::当前获取的函数指针所属的Vulkan实例(VkInstance)对象,如果为NULL说明要查询的目标函数指针不依赖于任何Vulkan实例。
- pName::要查询的目标函数名,必须以\0结束的UTF-8字符串。
vkGetInstanceProcAddr该函数本身是通过特定的平台和加载器(loader)获得的。一般加载库会导出函数符号,所以应用可通过链接加载器或者动态加载或者使用平台特定的加载函数来获得函数。
下表说明使用vkGetInstanceProcAddr的各种使用情况并且说明返回值。
vkGetInstanceProcAddr返回的函数指针类型是PFN_vkVoidFunction类型,查询的目标函数获取之后需要强制转换成目标函数类型。
Instance参数 | pName参数 | 返回值 |
*(意味着任何可用值,包括所有效值、无效值、NULL)
| NULL(nullptr) | 未定义 |
非空有效实例句柄 | * | 未定义 |
NULL(VK_NULL_HANDLE) | 目标函数指针 | |
NULL(VK_NULL_HANDLE) | 目标函数指针 | |
NULL(VK_NULL_HANDLE) | vkEnumerateInstanceLayerProperties | 目标函数指针 |
NULL(VK_NULL_HANDLE) | vkCreateInstance | 目标函数指针 |
非空有效实例句柄 | Vulkan核心函数名称 | 目标函数指针(该目标函数的第一个参数必须是可调度对象instance或者instance的子对象,比如 VkPhysicalDevice、VkDevice、VkQueue等) |
非空有效实例句柄 | 当前实例支持的扩展函数 | 目标函数指针(该目标函数的第一个参数必须是可调度对象instance或者instance的子对象,比如 VkPhysicalDevice、VkDevice、VkQueue等) |
非空有效实例句柄 | 当前设备支持的扩展函数 | 目标函数指针(该目标函数的第一个参数必须是可调度对象instance或者instance的子对象,比如 VkPhysicalDevice、VkDevice、VkQueue等) |
其他上面没有提到的情况 | NULL(nullptr) |
有效参数(隐示)
|
为支持系统中对于多个不同版本的Vulkan实现,通过调用vkGetInstanceProAddr函数获取的函数指针可能会针对不同的VkDevice对象和子对象调用进行不同的调度。可通过vkGetDeviceProcAddr获取设备专属的函数指针来避免任何调用VkDevice对象函数的内部开销。
PFN_vkVoidFunction vkGetDeviceProcAddr(
VkDevice device,
const char* pName
);
下面的表格显示了vkGetDeviceProcAddr函数的各种使用情况和返回值。返回值类型为PFN_vkVoidFunction,并且获取目标函数指针后必须转换成目标函数的类型,返回的函数指针的第一个参数必须是一个device句柄对象或者device的子对象。
Instance参数 | pName参数 | 返回值 |
NULL | *(意味着任何可用值,包括所有效值、无效值、NULL)
| 未定义 |
无效设备句柄 | * | 未定义 |
有效设备句柄 | NULL | 未定义 |
有效设备句柄 | 核心设备层的Vulkan函数 | 目标函数指针(该目标函数的第一个参数必须是可调度对象device或者device的子对象,比如 VkDevice、VkQueue、VkCommandBuffer等) |
有效设备句柄 | 支持的设备层扩展函数 | 目标函数指针(该目标函数的第一个参数必须是可调度对象device或者device的子对象,比如 VkDevice、VkQueue、VkCommandBuffer等) |
其他上面没有提到的情况 | NULL(nullptr) |
有效参数(隐示)
|
3.1.1 扩展物理设备核心功能
当物理支持的Vulkan设备版本大于等于当前已经增加了新功能的Vulkan版本时 物理设备的新核心功能就可以被使用。物理设备支持的Vulkan版本可通过调用vkGetPhysicalDeviceProperties函数获取。
3.1.2 通过设备扩展扩展物理设备
当支持VK_KHR_get_physical_device_properties2扩展,或者Vulkan实例和物理设备支持的版本都高于或等于1.1时,物理设备级别的扩展功能可通过激活设备扩展获得。在创建逻辑设备(VkDevice)之前可通过调用vkEnumerateDeviceExtensionProperties函数获取支持的扩展。
可以通过调用vkGetInstanceProcAddr函数获取物理设备级别的设备扩展提供的扩展函数。对于调用获得的函数指针可能对于不同的设备实现各不相同。应用一定不能将该物理设备不支持的扩展或者不支持的版本在该物理设备上激活。
一些设备扩展会提供额外的结构体,一般可将这些额外的结构体数据传入pNext参数中。
3.2实例
Vulkan中没有全局状态这一概念,对于每一个应用而言,其所有的状态都存储在一个VkInstance句柄对象中。创建一个VkInstance对象的同时会初始化Vulkan库并且允许应用调用Vulkan函数。
Vulkan实例通过VkInstance句柄来定义:
VK_DEFINE_HANDLE(VkInstance)
查询实例级别版本(Vulkan版本),可通过调用vkEnumerateInstanceVersion函数获取。
VkResult vkEnumerateInstanceVersion(
uint32_t* pApiVersion
);
返回值成功
|
有效参数(隐示)
|
pApiVersion是一个uint32_t类型的指针,代表支持的Vulkan版本。
3.2.1 Vulkan版本(插入章节,原文档无此章节)
Vulkan目前算是一套新的API,还有待扩展更多高级的使用扩展。有些扩展模块会随着版本的升高会转成核心模块。所以在初始化Vulkan是需要指定支持的版本。
Vulkan的版本分为3个部分
- 主版本(major version),用于整个规范的版本
- 副版本(minor version),用于新功能纳入了核心层
- 补丁版本(patch version),用于调试、修改和改进用法
Vulkan中一个完整版本号由一个uint32_t类型表示。uint32_t的32表示该无符号整数由32位二进制位组成。uint32_t版本号组成如下:
- 主版本,定义在31-22位上,最大可表示主版本号为1023。
- 副版本,定义在21-12位上,最大可表示副版本号为1023。
- 补丁版本,定义在11-0位上,最大可表示补丁号为4095。
Vulkan中可通过调用VK_VERSION_MAJOR获取版本号中的主版本号
#define VK_VERSION_MAJOR(version) ((uint32_t)(version) >> 22)
Vulkan中可通过调用VK_VERSION_MINOR获取版本号中的副版本号
#define VK_VERSION_MINOR(version) (((uint32_t)(version) >> 12) & 0x3ff)
Vulkan中可通过调用VK_VERSION_PATCH获取版本号中的补丁版本号
#define VK_VERSION_PATCH(version) ((uint32_t)(version) & 0xfff)
Vulkan中可通过调用VK_MAKE_VERSION并指定主版本号(major)和副版本号(minor)和补丁号(patch)创建uint32_t类型的Vulkan版本号。
#define VK_MAKE_VERSION(major, minor, patch) \
(((major) << 22) | ((minor) << 12) | (patch))
目前Vulkan中已经预定义了一部分版本号
VK_API_VERSION_1_0代表Vulkan 1.0.0版本
#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
VK_API_VERSION_1_1代表Vulkan 1.1.0版本
#define VK_API_VERSION_1_1 VK_MAKE_VERSION(1, 1, 0)
VK_API_VERSION_1_2代表Vulkan 1.2.0版本
#define VK_API_VERSION_1_2 VK_MAKE_VERSION(1, 2, 0)
3.2实例(继续~)
创建一个实例对象需要调用vkCreateInstance函数
VkResult vkCreateInstance(
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance
);
- pCreateInfo:: VkInstanceCreateInfo类型指针,包括创建Vulkan实例所需要的信息。
- pAllocator::如果不为空(nullptr),则必须传入一个有效的自定义内存分配器。空表示使用默认分配器
- pInstance::VkInstance类型指针,将会作为创建结果返回。
当运行vkCreateInstance函数时,Vulkan会去检查pCreateInfo中指定要被激活的层(layer)在当前Vulkan中是否支持,如果存在不支持的层vkCreateInstance将会返回VK_ERROR_LAYER_NOT_PRESENT错误码。之后会检查pCreateInfo中指定的要被激活的扩展(extension),如果存在不支持的扩展的话会返回VK_ERROR_EXTENSION_NOT_PRESENT错误码。当检查完毕后VkInstance对象将会被创建并赋到pInstance中。如果某个要被激活的扩展只有特定层(layer)支持的话,该层也需要激活。
返回值成功
失败
|
有效参数(隐示)
|
有效参数
|
VkInstanceCreateInfo结构体定义如下:
typedef struct VkInstanceCreateInfo {
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnabledLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
} VkInstanceCreateInfo;
- sType::当前结构体类型,必须为VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
- pNext::空(nullptr)或者为扩展提供的结构
- flags::为未来预留接口,当前为0
- pApplicationInfo::空(nullptr)或者指定VkApplicationInfo结构体指针。如果不是空可以帮助Vulkan更好的组织应用程序固有行为。
- enabledLayerCount::要激活的层数
- ppEnabledLayerNames::要激活的层名称数组。各名称必须为\0结束的UTF-8字符串。Vulkan对于层的加载顺序是按照该参数指定的数组顺序依次加载的。越在前面的层越接近应用,越往后越接近驱动。具体请看Layer章节(目前还没翻译)
- enabledExtensionCount::要激活的扩展数
有效值(隐示)
|
当创建Vulkan实例时,可能有时想要关闭某些检查验证。这是可以通过在VkInstanceCreateInfo机构中的pNext中添加一个VkValidationFlagsEXT结构体用于指定要关闭的检查。
typedef struct VkValidationFlagsEXT {
VkStructureType sType;
const void* pNext;
uint32_t disabledValidationCheckCount;
const VkValidationCheckEXT* pDisabledValidationChecks;
} VkValidationFlagsEXT;
- sType::用于表示当前结构体类型,必须是VK_STRUCTURE_TYPE_VALIDATION_FLAGS_EXT
- pNext::空或者是某些特定扩展提供的扩展结构体.
- disabledValidationCheckCount::要关闭的检查个数
有效值(隐示)
|
VkValidationFlagsEXT的定义如下:
typedef enum VkValidationCheckEXT {
VK_VALIDATION_CHECK_ALL_EXT = 0,
VK_VALIDATION_CHECK_SHADERS_EXT = 1,
VK_VALIDATION_CHECK_MAX_ENUM_EXT = 0x7FFFFFFF
} VkValidationCheckEXT;
- VK_VALIDATION_CHECK_ALL_EXT::关闭所有的验证检查
- VK_VALIDATION_CHECK_SHADERS_EXT::关闭着色器验证
当创建Vulkan实例时可以通过将VkValidationFeaturesEXT结构体数据加入VkInstanceCreateInfo结构体中的pNext来开启或关闭某些特性(Vaalidation feature)
typedef struct VkValidationFeaturesEXT {
VkStructureType sType;
const void* pNext;
uint32_t enabledValidationFeatureCount;
const VkValidationFeatureEnableEXT* pEnabledValidationFeatures;
uint32_t disabledValidationFeatureCount;
const VkValidationFeatureDisableEXT* pDisabledValidationFeatures;
} VkValidationFeaturesEXT;
- sType::当前结构体类型,必须是VK_STRUCTURE_TYPE_VALIDATION_FEATURES_EXT
- pNext::空或者是扩展结构体
- enabledValidationFeatureCount::要开启的特性数量
- pEnabledValidationFeatures::指向VkValidationFeatureEnableEXT类型数组,表示要开启的特性数组
- disabledValidationFeatureCount:: 要关闭的特性数量
- pDisabledValidationFeatures:: 指向VkValidationFeatureDisableEXT类型数组,表示要关闭的特性数组
有效参数(隐示)
|
VkValidationFeatureEnableEXT定义如下:
typedef enum VkValidationFeatureEnableEXT {
VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT = 0,
VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT = 1,
VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT = 2,
VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT = 3,
VK_VALIDATION_FEATURE_ENABLE_MAX_ENUM_EXT = 0x7FFFFFFF
} VkValidationFeatureEnableEXT;
- VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT::表示开启GPU辅助验证(GPU-assisted validation),当开启后着色器会生成额外的验证信息。该特性默认关闭。
- VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_RESERVE_BINDING_SLOT_EXT::表示验证层(validaton layers)会保留一个自己使用的描述符集(descriptor set,描述符集为外部与shader内部之间的数据桥梁)。VkPhysicalDeviceLimits::maxBoundDescriptorSets的值要比设备报告的值小1(表示不包括该特性的描述符集)。如果设备支持绑定一个描述符集,验证层不会进行GPU辅助验证。该特性默认关闭。在开启该特性时GPU辅助特性也需要开启。
- VK_VALIDATION_FEATURE_ENABLE_BEST_PRACTICES_EXT::表示开启Vulkan最佳实践验证(Vulkan best-practices validation)。开启后将会输出常见API滥用警告信息。该特性默认关闭。
- VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT::表示该层将会处理着色器中的debugPrintfEXT操作和将结果发送到调试回调中。该特性默认关闭。当VK_VALIDATION_FEATURE_ENABLE_GPU_ASSISTED_EXT特性被开启的情况下,禁止开启VK_VALIDATION_FEATURE_ENABLE_DEBUG_PRINTF_EXT特性。
VkValidationFeatureDisableEXT定义如下:
typedef enum VkValidationFeatureDisableEXT {
VK_VALIDATION_FEATURE_DISABLE_ALL_EXT = 0,
VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT = 1,
VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT = 2,
VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT = 3,
VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT = 4,
VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT = 5,
VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT = 6,
VK_VALIDATION_FEATURE_DISABLE_MAX_ENUM_EXT = 0x7FFFFFFF
} VkValidationFeatureDisableEXT;
- VK_VALIDATION_FEATURE_DISABLE_ALL_EXT::关闭所有验证检查
- VK_VALIDATION_FEATURE_DISABLE_SHADERS_EXT::表示关闭着色器验证,该特性默认开启。
- VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT::表示关闭线程安全验证,该特性默认开启。
- VK_VALIDATION_FEATURE_DISABLE_API_PARAMETERS_EXT::表示关闭无效参数验证,该特性默认开启
- VK_VALIDATION_FEATURE_DISABLE_OBJECT_LIFETIMES_EXT::表示关闭对象生命周期验证,该特性默认开启。
- VK_VALIDATION_FEATURE_DISABLE_CORE_CHECKS_EXT::表示关闭核心验证,该特性默认开启。当该特性关闭时,着色器验证和GPU辅助验证特性也将关闭。
- VK_VALIDATION_FEATURE_DISABLE_UNIQUE_HANDLES_EXT::表示关闭保护并防止重复可派遣对象句柄特性,该特性默认开启。
注::
1.关闭类似于参数验证和对象生命验证后可能会导致其他验证层的错误或者崩溃。某些验证层的验证是已经假设输入是正确有效的了,并不会总是重新验证。
2.VK_EXT_validation_features扩展中包括VK_EXT_validation_flags扩展的所有功能。
VkApplicationInfo结构体的定义如下:
typedef struct VkApplicationInfo {
VkStructureType sType;
const void* pNext;
const char* pApplicationName;
uint32_t applicationVersion;
const char* pEngineName;
uint32_t engineVersion;
uint32_t apiVersion;
} VkApplicationInfo;
- sType::表示当前结构体类型,必须为VK_STRUCTURE_TYPE_APPLICATION_INFO
- pNext::空或者为扩展结构体链
- pApplicationName::空或者是以\0结束的UTF-8字符串,表示该应用的名称。
- applicationVersion::表示自定义的应用开发版本
- pEngineName:: 空或者是以\0结束的UTF-8字符串,表示创建应用的引擎名称。
- engineVersion:: 表示自定义的引擎开发版本
- apiVersion::表示该应用要使用的Vulkan版本。该版本必须是应用预计使用的Vulkan最高版本。创建实例时该版本参数中补丁号将会忽略,只有主版本号和副版本号起作用。
如果系统支持的Vulkan版本为1.0的话,当apiVersion中指定的版本号高于1.0的话,将会返回VK_ERROR_INCOMPATIBLE_DRIVER错误码。当系统支持Vulkan的版本为1.1或高于1.1时,无论apiVersion中的值是多少都不会返回VK_ERROR_INCOMPATIBLE_DRIVER错误码。
注::
1.因为在创建Vulkan实例时Vulkan 1.0的版本可能会返回VK_ERROR_INCOMPATIBLE_DRIVER错误码,所以在创建实例之前最好查询一下当前支持的Vulkan版本。可通过调用vkGetInstanceProcAddr函数查询vkEnumerateInstanceVersion函数指针,如果返回为空说明当前Vulkan版本为1.0,如果不为空则可以放心调用vkEnumerateInstanceVersion来获取Vulkan的版本了。(该方法也是Vulkan官方推荐的方法,在官方示例中有专门该方法的源码,正常的话源码位于Vulkan_SDK_Path\Samples\API-Samples\16-vulkan_1_1中)。
只要Vulkan的版本大于等于1.1,应用就可以使用与设备或物理设备中的所支持的Vulkan版本不一样的版本。物理设备支持的Vulkan版本可通过调用
vkGetPhysicalDeviceProperties函数附上VkPhysicalDeviceProperties结构体获取,位于VkPhysicalDeviceProperties中apiVersion属性中。
注::
1. Khronos(Vulkan)的验证层将会把apiVersion版本作为应用的最高目标版本对待,并使用最低版本来验证API,如果应用尝试使用高于apiVersion版本的功能的话,就会触发一个验证错误。
例如,如果系统支持的Vulkan 1.1版本,此时有三个物理设备分别支持Vulkan 1.0,
Vulkan 1.1,Vulkan 1.2的话。如果此时创建Vulkan实例时指定的(apiVersion)是Vulkan 1.2版本的话,应用可以进行如下使用:
- Vulkan 1.0的功能可以被实例和所有物理设备使用
- Vulkan 1.1的功能可以被实例和支持Vulkan 1.1和Vulkan 1.2版本的物理设备使用。
- Vulkan 1.2的功能能被支持Vulkan 1.2版本的物理设备支持。
如果现在我们创建Vulkan实例的版本(apiVersion)指定成Vulkan 1.1版本的话,这时就变成应用禁止使用支持Vulkan 1.2的物理设备上的Vulkan 1.2的功能了。
如果隐示层不支持该版本的话必须将其关闭。
注::
1.如果在创建Vulkan实例时VkInstanceCreateInfo::pApplicationInfo为空或者apiVersion为0的话,这相当于指定apiVersion为VK_MAKE_VERSION(1,0,0) (Vulkan 1.0)实现同等价的。
有效参数(隐示)
|
通过调用vkDestroyInstance函数销毁一个Vulkan实例
void vkDestroyInstance(
VkInstance instance,
const VkAllocationCallbacks* pAllocator
);
- Instance::是要销毁的实例句柄
- pAllocator::控制内存分配,将会在Memory Allocation章节讲解(目前未翻译,第10章内容),如果使用的是Vulkan默认分配器,该参数为空(nullptr)。
有效参数(隐示)
|
有效参数
|
同步
|
(๑>ڡ<)☆ 本章完 ヾ(*´▽‘*)ノ