Instance的意义
我们使用Vulkan的第一步和OpenGL一样,都需要初始化函数库,OpenGL用一些函数例如glutinit之类的就可以完成,但是在Vulkan里面你需要通过创建 instance 来完成上面的事情,在创建 instance 的时候,我们可以通过设置不同参数来初始化一个VkInstance
来提供一个包含我们想要的功能的库(比如说用来屏幕绘制的交换链,如果只是离线渲染不需要呈现到屏幕来,那就不需要这个功能)。
1 Instance的创建的销毁
1.1 创建Instance需要的结构体
我们需要用到VkInsatnceCreateInfo
结构体,该结构体定义如下。
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
指定了存着程序信息的VkApplicationInfo
结构体 -
enabledLayerCount
用来告诉Instance需要的Layer的个数 -
ppEnabledLayerNames
用来告诉Instance需要的Layer名字,是个字符串数组,创建时会根据上面提供的参数从该指针读取相应个数 -
enabledExtensionCount
和Layer一样,不过是扩展的个数 -
ppEnabledExtensionNames
和Layer,用来提供扩展的名字
1.2 创建Insatnce需要用到的函数
VkResult vkCreateInstance (
const VkInstanceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkInstance* pInstance )
参数详解:
-
pCreateInfo
Instance创建时所需要的CreateInfo,也就是VkInstanceCreateInfo
结构体 -
pAllocator
自定义内存分配回调,设置为nullptr
就好 -
pInstance
被创建的Instance变量
1.3 例子:简单的创建Instance
// 创建VkInstanceCreateInfo需要用到的结构体
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_1; // 使用的Vulkan Api版本
// 创建Instance所需要的结构体
VkInstanceCreateInfo createInfo = {};
createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createInfo.pApplicationInfo = &appInfo;
createInfo.enabledLayerCount =0;
createInfo.enabledExtensionNames=0;
createInfo.pNext=nullptr;
createInfo.ppEnabledLayerNames=nullptr;
createInfo.ppEnabledExtensionNames=nullptr;
createInfo.flags=0;
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
1.4 告诉Instance你要使用的扩展
这里特别注意!!!你要在你引用的glfw头文件前加一个宏定义#define GLFW_INCLUDE_VULKAN
因为glfw是默认支持OpenGL的
启用glfw扩展:
因为我们使用的glfw需要使用一些扩展,用下面代码获取glfw扩展
uint32_t glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
//这时我们需要把有关于createInfo的extension部分改成如下所示
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
将glfw所需要的扩展打印出来
更建议用下面的方式存扩展
// 因为以后会有很多扩展,这里建议用vector存起来
vector extensions_required;
/*
..........中间省略了将各种扩展push_back进extensions_required的过程
*/
createInfo.enabledExtensionCount = extensions_required.size();
createInfo.ppEnabledExtensionNames = extensions_required.data();
1.5 检查Vulkan是否支持扩展
但是我们并不知道使用的Vulkan版本是否支持上面的扩展,所以我们需要查询
uint32_t extensionCount = 0;
// 把第三个个参数设置为nullptr,下面函数只返回可用扩展的个数
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
std::vector extensions(extensionCount);
// 然后再用同一个函数获取extensionCount个可用扩展。
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
// 然后讲extensions里的内容输出查看
std::cout << "available extensions:" << std::endl;
for (const auto& extension : extensions) {
std::cout << "\t" << extension.extensionName << std::endl;
}
该代码输出如下图所示,,输出会因电脑还有系统不同而变化:
2 销毁Instance所用到的函数
void vkDestroyInstance(
VkInstance instance,
const VkAllocationCallbacks* pAllocator);
参数详解:
-
instance
之前创建成功的Instance -
pAllocator
自定义分配回调函数,和创建一样设置为nullptr
这时候我们综合上面的知识,写一个Instance类,为什么要写,因为后面会有很多其他的Vulkan变量,例如VkDevice
等等,他们的创建都需要相应的Vk×××CreateInfo,如果我们要挨个手动管理他们各自的创建信息还有其他一些东西太麻烦了,我们要把依附性强的东西放到一个类里面,让类来管理比较轻松一点
class Instance
{
public:
VkInstance instance=nullptr;
VkApplicationInfo appInfo=
{
VK_STRUCTURE_TYPE_APPLICATION_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
"Vulkan Application",// const char* pApplicationName;
VK_MAKE_VERSION(1,0,0), // uint32_t applicationVersion;
"No Engine", // const char* pEngineName;
VK_MAKE_VERSION(1,0,0), // uint32_t engineVersion;
VK_API_VERSION_1_1 // uint32_t apiVersion;
};
VkInstanceCreateInfo createInfo={
VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, // VkStructureType sType;
nullptr, // const void* pNext;
0, // VkInstanceCreateFlags flags;
&appInfo, // const VkApplicationInfo* pApplicationInfo;
0, // uint32_t enabledLayerCount;
nullptr,// const char* const* ppEnabledLayerNames;
0,// uint32_t enabledExtensionCount;
nullptr// const char* const* ppEnabledExtensionNames;
};
Instance():isCreated(false)
{
// get the available extension and layers
queryAvailableExtensions();
queryAvailableLayers();
// enable the validation layers
if (enableValidationLayers)
{
enableLayer("VK_LAYER_LUNARG_standard_validation");
enableExtension(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
}
}
~Instance()
{
if(auto_destroy)
destroy();
}
// enable extensions fcuntion
void enableExtension(const char * extension)
{
if (extensions_available.count(string(extension)))
extensions_required.push_back(extension);
else
std::cerr << "Error: " << extension << " Required but Not Support !" << endl;
}
// enable layers function
void enableLayer(std::vector requiredlayers)
{
for (auto& layer : requiredlayers)
enableLayer(layer);
}
void enableLayer(const char * layer)
{
if (layers_available.count(string(layer)))
layers_required.push_back(layer);
else
std::cerr << "Error: " << layer << " Required but Not Support !" << endl;
}
// create the instance
VkResult creat(const VkAllocationCallbacks* pAllocator = nullptr)
{
if (isCreated)
return VK_SUCCESS;
else
{
VkResult result;
// prepare the extension of need;
createInfo.enabledExtensionCount = static_cast(extensions_required.size());
if (createInfo.enabledExtensionCount)
createInfo.ppEnabledExtensionNames = extensions_required.data();
// prepare the layer of need
createInfo.enabledLayerCount = static_cast(layers_required.size());
if (createInfo.enabledLayerCount)
createInfo.ppEnabledLayerNames = layers_required.data();
// if fail to create Instance
if ((result = vkCreateInstance(&createInfo, pAllocator, &instance)) != VK_SUCCESS)
{
throw string("Error: fail to create Vulkan Instance. \n") + string("Detail: vkCreateInstance() return ") + toString(result);
}
// succeed to create Instance
else
{
isCreated = true;
std::cout << "Info: succeed to create Vulkan Instance.\n";
}
return result;
}
}
// destroy the instance
void destroy(const VkAllocationCallbacks* pAllocator = nullptr)
{
if (isCreated)
{
vkDestroyInstance(instance, pAllocator);
isCreated = false;
}
}
private:
bool isCreated = false;
std::vector extensions_required;
std::vector layers_required;
std::map extensions_available;
std::map layers_available;
bool auto_destroy = true;
// get the available extensions
inline void queryAvailableExtensions()
{
uint32_t extensionCount = 0;
VkResult result;
result = vkEnumerateInstanceExtensionProperties(NULL,&extensionCount, nullptr);
if (result != VK_SUCCESS)
{
std::cerr << "Fatal: fail to query Vulkan available Extension ! " << endl
<< "vkEnumerateInstanceExtensionProperties() return " << toString(result);
return;
}
if (extensionCount > 0)
{
std::vector extensions(extensionCount);
vkEnumerateInstanceExtensionProperties(NULL, &extensionCount, extensions.data());
for (auto& extension : extensions)
extensions_available.insert(make_pair(extension.extensionName, extension));
}
else
cout << "Info: No Vulkan Extension Available ! " << endl;
}
// get the available layers
inline void queryAvailableLayers()
{
VkResult result;
uint32_t layerCount = 0;
result = vkEnumerateInstanceLayerProperties(&layerCount, nullptr);
if (result != VK_SUCCESS)
{
std::cerr << "Error: fail to query Vulkan available Layers" << endl
<< "vkEnumerateInstanceLayerProperties() return " << toString(result) << endl;
return;
}
if (layerCount > 0)
{
std::vector availableLayers(layerCount);
vkEnumerateInstanceLayerProperties(&layerCount, availableLayers.data());
for (auto& layer : availableLayers)
layers_available.insert(make_pair(layer.layerName, layer));
}
else
cout << "Info: No Vulkan Layer Available ! " << endl;
}
};