大家好,接下来将为大家介绍Vulkan:创建Vulkan实例。
与Vulkan
打交道,通常的步骤是创建一个intance
去初始化Vulkan library
。这个instance
是您的应用程序与Vulkan
库之间的连接桥梁,通常创建过程中,需要向驱动程序提供一些应用层的信息。
1、创建实例基本介绍
Vulkan API
使用vkInstance
对象来存储所有每个应用的状态。应用程序在执行任何其他Vulkan
操作之前必须创建一个Vulkan
实例,基本的Vulkan
架构看起来是这样的:
上面的图显示了一个Vulkan应用程序链接到一个被称为加载器(Loader)的Vulkan库。创建实例会初始化这个装载器Loader。加载器还会加载并初始化低层级的图形驱动程序Driver,通常由GPU硬件的供应商提供。
请注意在图表中提到的layers,它们也是被loader加载的。layers通常被用来执行validation验证操作。validation是驱动的错误校验。在Vulkan中,驱动程序比OpenGL等其他的API更加的轻量化,这正是因为驱动将validation功能交给layers代理的结果。同时layers也并不是必须的,而且在每一次创建实例的时候,layers可以被选择性的加载。
2、相关API介绍
vkCreateInstance
vkCreateInstance函数的原型为:
VkResult vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator, VkInstance* pInstance);
参数说明:
VkResult
- 函数的返回状态。VkInstanceCreateInfo
- 创建一个实例所需要的额外的信息,这是一个相当重要的结构体。VkAllocationCallbacks
- 用户可以设定自定义的内存分配函数,不指定的话,Vulkan会使用默认的NULL。VkInstance
- 如果instance实例能够被顺利的创建,这个就是实例的句柄。
VkInstanceCreateInfo 结构体
Vulkan创建对象的时候,总会有一个VkObjectCreateInfo参数。创建instance对象时,对应VkInstanceCreateInfo参数。
typedef struct VkInstanceCreateInfo{
VkStructureType sType;
const void* pNext;
VkInstanceCreateFlags flags;
const VkApplicationInfo* pApplicationInfo;
uint32_t enabledLayerCount;
const char* const* ppEnableLayerNames;
uint32_t enabledExtensionCount;
const char* const* ppEnabledExtensionNames;
}VkInstanceCreateInfo;
sType
- 指明这个结构体的类型。既然这是一个VkInstanceCreateInfo
结构体,你需要将其设置为VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO
。其目的如下:
由于sType总是结构体的第一个字段,该结构体的消费者总是能够轻易的确定它的类型,然后决定来如何处理它。
pNext
- 用于传递扩展指定的消息,该字段通常被设置为NULL
。
flags
- 当前没有flags被定义,将其设置为0。
pApplicationInfo
- 应用相关的结构体信息。
enabledLayerCount
和 ppEnabledLayerNames
- 本节接下来内容会讲。
enabledExtensionCount
和 ppEnabledExtensionNames
- 本节内容暂时不涉及。
VkApplicationInfo 结构体
这个结构体提供了应用的一些由Vulkan实现的基本的信息。
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
和 pNext
- 同 vkInstanceCreateInfo 结构体一样
。
pApplicationName
, applicationVersion
, pEngineName
, engineVersion
- 这些是非必要填写的字段。如果需要的话,这些是应用程序可以提供的自由字段。 一些 tools, loaders, layers, 或者 drivers 的实现可能会用这些字段进行debugging或者出报告。driver甚至可以使用这些字段来更改自身的行为,这取决于当前的应用程序。
apiVersion
- vulkan API的版本。
3、一个简单的示例程序
// 01_instance_creation.cpp
#define GLFW_INCLUDE_VULKAN
#include
#include
#include
#include
const int WIDTH = 800;
const int HEIGHT = 600;
class HelloTriangleApplication {
public:
void run() {
initWindow();
initVulkan();
mainLoop();
cleanup();
}
private:
GLFWwindow* window;
VkInstance instance;
void initWindow() {
glfwInit();
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}
void initVulkan() {
createInstance();
}
void mainLoop() {
while (!glfwWindowShouldClose(window)) {
glfwPollEvents();
}
}
void cleanup() {
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}
void createInstance() {
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.enabledLayerCount = 0;
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
}
};
int main() {
HelloTriangleApplication app;
try {
app.run();
} catch (const std::exception& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
C++
代码详细介绍如下:
a:声明一个VKInstance对象,添加一个createInstance函数,并在initVulkan函数中调用。
private:
VkInstance instance;
void initVulkan() {
createInstance();
}
b:接下来创建VkApplicationInfo这个数据结构对象:
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;appInfo.pNext = nullptr;
appInfo.pApplicationName = "Hello Triangle";
appInfo.applicationVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.pEngineName = "No Engine";
appInfo.engineVersion = VK_MAKE_VERSION(1, 0, 0);
appInfo.apiVersion = VK_API_VERSION_1_0;
c:创建VkInstanceCreateInfo
结构体对象如下:
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
unsigned int glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
createInfo.enabledLayerCount = 0;
d:创建vulkan实例对象:
VkResult result = vkCreateInstance(&createInfo, nullptr, &instance);
e:检查instance
是否已经成功创建,我们不需要保存结果,仅仅使用 VK_SUCCESS 值来检测即可:
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
f:扩展的详细信息,我们首先需要知道有多少个扩展存在。可以通过将后一个参数置空来获取扩展数量:
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
std::cout << "available extensions:" << std::endl;
for (const auto& extension : extensions) {
std::cout << "\t" << extension.extensionName << std::endl;
}
g:正确销毁VkInstance:
void cleanup() {
vkDestroyInstance(instance, nullptr);
glfwDestroyWindow(window);
glfwTerminate();
}