原文地址: Vulakn-tutorial
Instance
Creating an instance
在 initVulkan
裏添加函數createInstance
:
void initVulkan() {
createInstance();
}
聲明變量:
private:
VDeleter<VkInstance> instance {vkDestroyInstance};
然後需要填充兩個結構體: VkApplicationInfo和 VkInstanceCreateInfo
VkApplicationInfo 是一個可選項,它提供的一些有用的信息可以使驅動對我們的應用進行優化。
(1)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 ;
填充 :
VkApplicationInfo appInfo = {};
appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
appInfo.pApplicationName = "Hello Triangle"; // 自定義
appInfo.applicationVersion = 1 //自定義
appInfo.pEngineName = "No Engine"; //自定義
appInfo.engineVersion =1; //自定義
appInfo.apiVersion = VK_API_VERSION_1_0;
說明: 幾乎所有VkXXXInfo
結構都有sType
字段,同樣它們的值有一個固定模式:VK_STRUCTURE_TYPE XXX_INFO
. apiVersion
是Vulkan的版本號,在vulkan.h
中有如下定義 :
// Vulkan 1.0 version number
#define VK_API_VERSION_1_0 VK_MAKE_VERSION(1, 0, 0)
所以此處apiVersion
值 爲VK_API_VERSION_1_0.
(2) VkInstanceCreateInfo
結構如下:
VkInstanceCreateInfo createinfo = {};
createinfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
createinfo.pNext = NULL;
createinfo.flags = 0;
createinfo.pApplicationInfo = &appinfo; //我們在(1) 中創建的
說明: 在Vulkan中,幾乎所有需要創建的 XXX對象,都要填充類似VkXXXCreateInfo結構體。VkInstanceCreateInfo
告訴Vulkan驅動我們將使用的全局擴展(global extensions )和驗證層(global validation layers )。
flag
保留,未來可能使用(for future use),保持默認或者賦值爲0.
後面還有兩個字段enabledExtensionCount
,enabledLayerCount
,表示使全局擴展(extension)和驗證層(Validation layers)的數量,以及它們的名字(後面還將詳細介紹具體的extension 和 layers)
因爲Vulkan是跨平臺的,所以它需要類似於“插件”一樣的擴展來和窗體系統(window system)進行聯繫。
glfw 內置擁有獲取擴展的方法:
unsigned int glfwExtensionCount = 0;
const char** glfwExtensions;
glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionCount);
createInfo.enabledExtensionCount = glfwExtensionCount;
createInfo.ppEnabledExtensionNames = glfwExtensions;
先將Validation layers置0,後面我們再討論這個問題。
createInfo.enabledLayerCount = 0;
在創建Instance之前先來看一下Vulkan的函數返回值VkResult:
typedef enum VkResult {
VK_SUCCESS = 0,
VK_NOT_READY = 1,
VK_TIMEOUT = 2,
VK_EVENT_SET = 3,
VK_EVENT_RESET = 4,
VK_INCOMPLETE = 5,
VK_ERROR_OUT_OF_HOST_MEMORY = -1,
VK_ERROR_FEATURE_NOT_PRESENT = -8,
VK_SUBOPTIMAL_KHR = 1000001003,
VK_ERROR_OUT_OF_DATE_KHR = -1000001004,
…
…
} VkResult;
成功值:
VK_SUCCESS: 成功執行。
VK_NOT_READY: 尚未準備好。
VK_TIMEOUT: 超時。
VK_INCOMPLETE: 對於真正需要的結果A來說,返回的結果B小於A的數量。
VK_SUBOPTIMAL_KHR: Swap Chain 不能和Surface 完全匹配,但任然能用。
其他…
錯誤值:
VK_ERROR_FORMAT_NOT_SUPPORTED 設備不支持的格式。.
VK_ERROR_FRAGMENTED_POOL 由於碎片的原因 Pool分配失敗。
VK_ERROR_SURFACE_LOST_KHR Surface 不再可用。
其他….
創建Instance:
if (vkCreateInstance(&createInfo, nullptr, &instance) != VK_SUCCESS) {
throw std::runtime_error("failed to create instance!");
}
這樣Instance就創建好了,運行一下你的程序,看看Instacne是否創建成功。
Checking for extension support
本節代碼中並未使用這種方法,但你可以分別打印出它和glfw獲取的extension有什麼區別。
雖然glfw提供了獲取extension的內置方法,我們同樣可以使用vulkan核心API中的方法來檢測當前平臺所支持的extension:
VkResult vkEnumerateInstanceExtensionProperties(
const char* pLayerName,
uint32_t* pPropertyCount,
VkExtensionProperties* pProperties);
它接收三個參數:
- pLayerName: 是一個Validation layer,用來過濾extension ,這裏先置爲nullptr。
- pPropertyCount: 返回extension 的數量。
- pProperties : extension的具體細節,如果這個值爲nullptr,則,函數只返回extension的數量,即pPropertyCount,否則返回pPropertyCount個VkExtensionProperties。
首先獲取extension的數量:
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
用這個數量創建容器:
std::vector<VkExtensionProperties> extensions(extensionCount);
最後獲取平臺上支持的extension:
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data());
打印出來看看每個extension具體是什麼 :
std::cout << "available extensions:" << std::endl;
for (const auto& extension : extensions) {
std::cout << "\t" << extension.extensionName << std::endl;
完整代碼:
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#include <iostream>
#include <stdexcept>
#include <functional>
const int WIDTH = 800;
const int HEIGHT = 600;
template <typename T>
class VDeleter {
public:
VDeleter() : VDeleter([](T, VkAllocationCallbacks*) {}) {}
VDeleter(std::function<void(T, VkAllocationCallbacks*)> deletef) {
this->deleter = [=](T obj) { deletef(obj, nullptr); };
}
VDeleter(const VDeleter<VkInstance>& instance, std::function<void(VkInstance, T, VkAllocationCallbacks*)> deletef) {
this->deleter = [&instance, deletef](T obj) { deletef(instance, obj, nullptr); };
}
VDeleter(const VDeleter<VkDevice>& device, std::function<void(VkDevice, T, VkAllocationCallbacks*)> deletef) {
this->deleter = [&device, deletef](T obj) { deletef(device, obj, nullptr); };
}
~VDeleter() {
cleanup();
}
T* operator &() {
cleanup();
return &object;
}
operator T() const {
return object;
}
private:
T object{VK_NULL_HANDLE};
std::function<void(T)> deleter;
void cleanup() {
if (object != VK_NULL_HANDLE) {
deleter(object);
}
object = VK_NULL_HANDLE;
}
};
class HelloTriangleApplication {
public:
void run() {
initWindow();
initVulkan();
mainLoop();
}
private:
GLFWwindow* window;
VDeleter<VkInstance> instance{vkDestroyInstance};
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 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;
unsigned int 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::runtime_error& e) {
std::cerr << e.what() << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}