操做系统: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