Vulkan Tutorial 02 編寫Vulkan應用程序框架原型

操做系統:Windows8.1html

顯卡:Nivida GTX965Mios

開發工具:Visual Studio 2017git


General structure

在上一節中,咱們建立了一個正確配置、可運行的的Vulkan應用程序,並使用測試代碼進行了測試。本節中咱們從頭開始,使用以下代碼構建一個基於GLFW的Vulkan應用程序原型框架的雛形。github

#include <vulkan/vulkan.h>

#include <iostream>
#include <stdexcept>
#include <functional>

class HelloTriangleApplication {
public:
    void run() {
        initVulkan();
        mainLoop();
        cleanup();
    }

private:
    void initVulkan() {

    }

    void mainLoop() {

    }

    void cleanup() {

    }
};

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;
}

首先從LunarG SDK中添加Vulkan頭文件,它提供了購機愛你Vulkan應用程序須要的函數、結構體、和枚舉。咱們包含stdexceptiostream頭文件用於拋出異常信息,而functional頭文件用於資源管理部分支持lambda表達式。app

 

程序被封裝到一個類中,該類結構將會存儲Vulkan私有成員對象,並添加基本的函數來初始化他們。首先會從initVulkan函數開始調用。當一切準備好,咱們進入主循環開始渲染幀。咱們將會加入mainLoop函數包含loop循環調用,該循環調用直到GLFW窗體管理纔會中止。當窗體關閉而且mainLoop返回時,咱們須要釋放咱們已經申請過的任何資源,該清理邏輯在cleanup函數中去定義。框架

 

程序運行期間,若是發生了任何嚴重的錯誤異常,咱們會拋出std::runtime_error 並註明異常描述信息,這個異常信息會被main函數捕獲及打印提示。很快你將會遇到一個拋出error的例子,是關於Vulkan應用程序不支持某個必要的擴展功能。ide

 

基本上在以後的每個小節中都會從initVulkan函數中增長一個新的Vulkan函數調用,增長的函數會產生Vulkan objects 並保存爲類的私有成員,請記得在cleanup中進行資源的清理和釋放。函數

Resource management


 咱們知道經過malloc分配的每個內存快在使用完以後都須要free內存資源,每個咱們建立的Vulkan object不在使用時都須要明確的銷燬。在C++中能夠利用<memory> 完成 auto 資源管理,可是在本節中,選擇明確編寫全部的內存的分配和釋放操做,其主要緣由是Vulkan的設計理念就是明確每一步操做,清楚每個對象的生命週期,避免可能存在的未知代碼形成的異常。工具

 

固然在本節以後,咱們能夠經過重載std::shared_ptr來實現auto 資源管理。對於更大致量的Vulkan程序,建議遵循RAII的原則維護資源的管理。oop

 

Vulkan對象能夠直接使用vkCreateXXX系函數建立,也能夠經過具備vkAllocateXXX等功能的一個對象進行分配。確保每個對象在不使用的時候調用vkDestroyXXXvkFreeXXX銷燬、釋放對應的資源。這些函數的參數一般因不一樣類型的對象而不一樣,可是他們共享一個參數:pAllocator。這是一個可選的參數,Vulkan容許咱們自定義內存分配器。咱們將在本教程忽略此參數,始終以nullptr做爲參數。

Integrating GLFW


若是咱們開發一些不須要基於屏幕顯示的程序,那麼純粹的Vulkan自己能夠完美的支持開發。可是若是建立一些讓人興奮的可視化的內容,咱們就須要引入窗體系統GLFW,並將#include <vulkan/vulkan.h> 進行相應的替換。

#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>

在新版本的GLFW中已經提供了Vulkan相關的支持,詳細的使用建議參閱官方資料。

經過替換,將會使用GLFW對Vulkan的支持,並自動加載Vulkan的頭文件。在run函數中添加一個initWindow函數調用,並確保在其餘函數調用前優先調用。咱們將會經過該函數完成GLFW的窗體初始化工做。

void run() {
    initWindow();
    initVulkan();
    mainLoop();
    cleanup();
}

private:
    void initWindow() {

    }

initWindow中的第一個調用是glfwInit(),它會初始化GLFW庫。由於最初GLFW是爲OpenGL建立上下文,因此在這裏咱們須要告訴它不要調用OpenGL相關的初始化操做。

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);

特別注意窗口大小的設置,稍後咱們會調用,如今使用另外一個窗口提示來僅用它。

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

如今剩下的就是建立實際的窗體。添加一個GLFWwindow*窗體,私有類成員存儲其引用並初始化窗體:

window = glfwCreateWindow(800, 600, "Vulkan", nullptr, nullptr);

前三個參數定義窗體的寬度、高度和Title。第四個參數容許制定一個監聽器來打開窗體,最後一個參數與OpenGL有關,咱們選擇nullptr。

 

使用常量代替硬編碼寬度和高度,由於咱們在後續的內容中會引用該數值屢次。在HelloTriangleApplication類定義之上添加如下幾行:

const int WIDTH = 800;
const int HEIGHT = 600;

並替換窗體建立的代碼語句爲:

window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);

你如今應該有一個以下所示的initWindow函數:

void initWindow() {
    glfwInit();

    glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);

    window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
}

保持程序運行,直到發生錯誤或者窗體關閉,咱們須要向mainLoop函數添加事件循環,以下所示:

void mainLoop() {
    while (!glfwWindowShouldClose(window)) {
        glfwPollEvents();
    }
}

這段代碼應該很容易看懂。它循環並檢查GLFW事件,直到按下X按鈕,或者關閉窗體。該循環結構稍後會調用渲染函數。

 

一旦窗體關閉,咱們須要經過cleanup函數清理資源、結束GLFW自己。

void cleanup() {
    glfwDestroyWindow(window);

    glfwTerminate();
}

運行程序,咱們應該會看到一個名爲Vulkan的白色窗體,直到關閉窗體終止應用程序。

ok,到如今咱們已經完成了一個Vulkan程序的骨架原型,在下一小節咱們會建立第一個Vulkan Object!

 

獲取工程代碼 GitHub checkout

相關文章
相關標籤/搜索