一、概述
最近因为工作需要开始学习Vulkan的相关知识,作为初学者,发现相对较好的学习资料莫过于vulkan-tutorial,在自己学习Vulkan的过程中,决定将自己的理解记录下来,一是为了加深记忆,二是为了分享给大家一起探讨学习,因此有了本系列文章,开发环境搭建是本系列文章的第一篇。
二、开发环境搭建
2.1 安装Microsoft Visual Studio Community 2022
Vulkan作为跨平台的图形API,直接支持的开发语言为c/c++,最合适(经济)的开发平台是Windows,因此我选择免费的开发工具Microsoft Visual Studio Community 2022,安装过程并不复杂,唯一要注意的是要选择使用C++的桌面开发相关组件。
2.2 下载Vulkan SDK并安装
从官网下载最新的SDK,当前最新版本为1.3.243.0,双击运行安装程序,只需一直点击下一步就行,唯一要注意的是选择组件,为了避免遗漏,这里选择安装所有的组件:
安装成功后在开始菜单中可以找到Vulkan Cube程序,运行结果如下:
同时安装程序为自动完成环境变量设置,环境变量VK_SDK_PATH和VULKAN_SDK都是指向SDK的安装位置,其次Path环境变量也包含SDK的安装位置。
2.3 新建窗口项目
启动Visual Studio新建Windows 桌面向导:
点击下一步,输入项目名称,创建时选择桌面应用程序和 空项目:
在解决方案资源管理器中右键点击刚刚新建的项目,进入属性设置页面,C++语言标准设置为ISO C++17 标准(std:c++17):
将$(VULKAN_SDK)\Include添加到附加包含目录中,也就是将Vulkan SDK的头文件目录添加到项目的头文件搜索目录中:
将$(VULKAN_SDK)\Lib添加到附加库目录中,也就是将vulkan动态库路径添加到项目动态库搜索目录中:
最后将项目要依赖的vulkan-1.lib添加到附加依赖项中:
注意这里没有添加glfw的依赖,因为本系列笔记使用Win32 API创建窗口,没有使用glfw。
2.4 编写窗口代码
新建源文件main.cpp,在源文件中添加相关头文件:
#include <windows.h>
#include <vulkan/vulkan.h>
#define GLM_FORCE_RADIANS
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/vec4.hpp>
#include <glm/mat4x4.hpp>
#include <malloc.h>
#include <tchar.h>
创建窗口需要windows.h
,Vulkan相关的使用需要vulkan/vulkan.h
,矩阵和向量运算需要使用glm相关的头文件glm/vec4.hpp
和glm/mat4x4.hpp
,分配栈内存需要malloc.h
,使用Unicode字符相关方法需要tchar.h
。
void TRACE(LPCTSTR lpszFmt, ...) {
va_list args;
va_start(args, lpszFmt);
int len = _vsctprintf(lpszFmt, args) + 1;
TCHAR* lpszBuf = (TCHAR*)_malloca(len * sizeof(TCHAR));
if (lpszBuf != NULL) {
_vstprintf_s(lpszBuf, len, lpszFmt, args);
OutputDebugString(lpszBuf);
}
va_end(args);
_freea(lpszBuf);
}
TRACE
方法主要封装OutputDebugString
,便于输出调试信息,类似于Android的log输出,调试信息不是输出到控制台中,而是通过DebugView或Visual Studio的即时窗口查看。该方法参考自OutputDebugString方便格式化WIN32封装。
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
该方法为Win32的窗口消息回调,当窗口接受鼠标和按键信息时,都会回调这个方法进行处理,这里不过多展开,详细介绍可参考Win32 和 C++ 入门 - Win32 apps | Microsoft Learn。
int WINAPI WinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nShowCmd) {
LPCWSTR window_class = L"Learning Vulkan Class";
LPCWSTR window_title = L"Learning Vulkan";
int window_width = 800;
int window_height = 600;
WNDCLASSEX wcx{};
wcx.cbSize = sizeof(wcx);
wcx.style = CS_HREDRAW | CS_VREDRAW;
wcx.lpfnWndProc = WindowProc;
wcx.cbClsExtra = 0;
wcx.cbWndExtra = 0;
wcx.hInstance = hInstance;
wcx.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcx.hCursor = LoadCursor(NULL, IDC_ARROW);
wcx.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcx.lpszMenuName = NULL;
wcx.lpszClassName = window_class;
wcx.hIconSm = LoadIcon(hInstance, IDI_APPLICATION);;
if (!RegisterClassEx(&wcx)) {
MessageBox(NULL,
L"Call to RegisterClassEx failed!",
L"Learning Vulkan",
NULL);
return 1;
}
WinMain
方法为Win32窗口应用程序的入口函数,和控制台应用程序入口函数main
对应。接下的步骤为注册窗口,窗口注册详细介绍参考创建窗口 - Win32 apps | Microsoft Learn。
HWND hwnd = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
window_class,
window_title,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
window_width, window_height,
NULL,
NULL,
hInstance,
NULL
);
if (!hwnd) {
MessageBox(NULL,
L"Call to CreateWindow failed!",
L"Learning Vulkan",
NULL);
return 1;
}
ShowWindow(hwnd, nShowCmd);
UpdateWindow(hwnd);
CreateWindowEx
为创建窗口,创建完成后使用ShowWindow
进行显示,UpdateWindow
更新重绘窗口,类似于Android View的invalidate
。
uint32_t extensionCount = 0;
vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr);
TRACE(L"%d extensions supported\n", extensionCount);
glm::mat4 matrix;
glm::vec4 vec;
auto test = matrix * vec;
测试Vulkan SDK是否配置成功,一是枚举支持的实例(Instance)扩展数量,二是进行glm测试。
MSG msg{};
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
最后需要不断获取本窗口的信息,功能类似于glfw的glfwPollEvents
方法。如果没有while
循环,程序将直接结束退出。
运行程序可看到如下窗口:
在即时窗口中可以看到类似输出:
至此,Vulkan的开发环境算是搭建完成,后续的开发都会在此基础上进行。本文中创建的项目完整代码可在GitHub上查看。