操做系統:Windows8.1html
顯卡:Nivida GTX965Mios
開發工具:Visual Studio 2017git
在上一節中,咱們建立了一個正確配置、可運行的的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應用程序須要的函數、結構體、和枚舉。咱們包含stdexcept和iostream頭文件用於拋出異常信息,而functional頭文件用於資源管理部分支持lambda表達式。app
程序被封裝到一個類中,該類結構將會存儲Vulkan私有成員對象,並添加基本的函數來初始化他們。首先會從initVulkan函數開始調用。當一切準備好,咱們進入主循環開始渲染幀。咱們將會加入mainLoop函數包含loop循環調用,該循環調用直到GLFW窗體管理纔會中止。當窗體關閉而且mainLoop返回時,咱們須要釋放咱們已經申請過的任何資源,該清理邏輯在cleanup函數中去定義。框架
程序運行期間,若是發生了任何嚴重的錯誤異常,咱們會拋出std::runtime_error 並註明異常描述信息,這個異常信息會被main函數捕獲及打印提示。很快你將會遇到一個拋出error的例子,是關於Vulkan應用程序不支持某個必要的擴展功能。ide
基本上在以後的每個小節中都會從initVulkan函數中增長一個新的Vulkan函數調用,增長的函數會產生Vulkan objects 並保存爲類的私有成員,請記得在cleanup中進行資源的清理和釋放。函數
咱們知道經過malloc分配的每個內存快在使用完以後都須要free內存資源,每個咱們建立的Vulkan object不在使用時都須要明確的銷燬。在C++中能夠利用<memory> 完成 auto 資源管理,可是在本節中,選擇明確編寫全部的內存的分配和釋放操做,其主要緣由是Vulkan的設計理念就是明確每一步操做,清楚每個對象的生命週期,避免可能存在的未知代碼形成的異常。工具
固然在本節以後,咱們能夠經過重載std::shared_ptr來實現auto 資源管理。對於更大致量的Vulkan程序,建議遵循RAII的原則維護資源的管理。oop
Vulkan對象能夠直接使用vkCreateXXX系函數建立,也能夠經過具備vkAllocateXXX等功能的一個對象進行分配。確保每個對象在不使用的時候調用vkDestroyXXX和vkFreeXXX銷燬、釋放對應的資源。這些函數的參數一般因不一樣類型的對象而不一樣,可是他們共享一個參數:pAllocator。這是一個可選的參數,Vulkan容許咱們自定義內存分配器。咱們將在本教程忽略此參數,始終以nullptr做爲參數。
若是咱們開發一些不須要基於屏幕顯示的程序,那麼純粹的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