vulakn教程--Drawing a Triangle--Set up--Instance

原文地址: 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;
}
發佈了22 篇原創文章 · 獲贊 11 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章