# [译]Vulkan教程(04)基础代码

[译]Vulkan教程(04)基础代码

## General structure 通用结构

In the previous chapter you’ve created a Vulkan project with all of the proper configuration and tested it with the sample code. In this chapter we’re starting from scratch with the following code:

 1 #include
2
3 #include
4 #include
5 #include
6 #include
7
8 class HelloTriangleApplication {
9 public:
10     void run() {
11         initVulkan();
12         mainLoop();
13         cleanup();
14     }
15
16 private:
17     void initVulkan() {
18
19     }
20
21     void mainLoop() {
22
23     }
24
25     void cleanup() {
26
27     }
28 };
29
30 int main() {
31     HelloTriangleApplication app;
32
33     try {
34         app.run();
35     } catch (const std::exception& e) {
36         std::cerr << e.what() << std::endl;
37         return EXIT_FAILURE;
38     }
39
40     return EXIT_SUCCESS;
41 }


We first include the Vulkan header from the LunarG SDK, which provides the functions, structures and enumerations. The  stdexcept
and  iostream
headers are included for reporting and propagating errors. The  functional
headers will be used for a lambda functions in the resource management section. The  cstdlib
header provides the  EXIT_SUCCESS
and  EXIT_FAILURE
macros.

iostream

EXIT_FAILURE

The program itself is wrapped into a class where we’ll store the Vulkan objects as private class members and add functions to initiate each of them, which will be called from the  initVulkan
function. Once everything has been prepared, we enter the main loop to start rendering frames. We’ll fill in the  mainLoop
function to include a loop that iterates until the window is closed in a moment. Once the window is closed and  mainLoop
returns, we’ll make sure to deallocate the resources we’ve used in the  cleanup
function.

If any kind of fatal error occurs during execution then we’ll throw a  std::runtime_error
exception with a descriptive message, which will propagate back to the  main
function and be printed to the command prompt. To handle a variety of standard exception types as well, we catch the more general  std::exception
. One example of an error that we will deal with soon is finding out that a certain required extension is not supported.

。我们很快就要处理的一个error的例子是，发现某个要求的扩展不被支持。

Roughly every chapter that follows after this one will add one new function that will be called from  initVulkan
and one or more new Vulkan objects to the private class members that need to be freed at the end in  cleanup
.

## Resource management 资源管理

Just like each chunk of memory allocated with  malloc
requires a call to  free
, every Vulkan object that we create needs to be explicitly destroyed when we no longer need it. In modern C++ code it is possible to do automatic resource management through the utilities in the
header, but I’ve chosen to be explicit about allocation and deallocation of Vulkan objects in this tutorial. After all, Vulkan’s niche is to be explicit about every operation to avoid mistakes, so it’s good to be explicit about the lifetime of objects to learn how the API works.

After following this tutorial, you could implement automatic resource management by overloading  std::shared_ptr
for example. Using
RAII

to your advantage is the recommended approach for larger Vulkan programs, but for learning purposes it’s always good to know what’s going on behind the scenes.

）。对于大型的Vulkan程序，使用  RAII

Vulkan objects are either created directly with functions like

vkCreateXXX

, or allocated through another object with functions like

vkAllocateXXX

. After making sure that an object is no longer used anywhere, you need to destroy it with the counterparts

vkDestroyXXX

and

vkFreeXXX

. The parameters for these functions generally vary for different types of objects, but there is one parameter that they all share:  pAllocator
. This is an optional parameter that allows you to specify callbacks for a custom memory allocator. We will ignore this parameter in the tutorial and always pass  nullptr
as argument.

Vulkan对象要么是用
vkCreateXXX

vkAllocateXXX

vkDestroyXXX

vkFreeXXX

。这是一个可选参数，它允许你标识一个回调函数，用于以自定义的方式分配内存。本教程中我们将忽略这个参数，总是传给它 nullptr

## Integrating GLFW 集成GLFW

Vulkan works perfectly fine without a creating a window if you want to use it off-screen rendering, but it’s a lot more exciting to actually show something! First replace the  #include
line with

1 #define GLFW_INCLUDE_VULKAN
2 #include


That way GLFW will include its own definitions and automatically load the Vulkan header with it. Add a  initWindow
function and add a call to it from the  run
function before the other calls. We’ll use that function to initialize GLFW and create a window.

 1 void run() {
2     initWindow();
3     initVulkan();
4     mainLoop();
5     cleanup();
6 }
7
8 private:
9     void initWindow() {
10
11     }


The very first call in  initWindow
should be  glfwInit()
, which initializes the GLFW library. Because GLFW was originally designed to create an OpenGL context, we need to tell it to not create an OpenGL context with a subsequent call:

initWindow

，它初始化GLFW库。因为GLFW最初是被设计为创建OpenGL上下文而用的，我们需要在接下来的函数调用中告诉它不要创建OpenGL上下文：

glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);


Because handling resized windows takes special care that we’ll look into later, disable it for now with another window hint call:

glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);


All that’s left now is creating the actual window. Add a  GLFWwindow* window;
private class member to store a reference to it and initialize the window with:

，以保存对窗口的引用。用下述代码初始化窗口：

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


The first three parameters specify the width, height and title of the window. The fourth parameter allows you to optionally specify a monitor to open the window on and the last parameter is only relevant to OpenGL.

It’s a good idea to use constants instead of hardcoded width and height numbers because we’ll be referring to these values a couple of times in the future. I’ve added the following lines above the  HelloTriangleApplication
class definition:

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


and replaced the window creation call with

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


You should now have a  initWindow
function that looks like this:

1 void initWindow() {
2     glfwInit();
3
4     glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
5     glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
6
7     window = glfwCreateWindow(WIDTH, HEIGHT, "Vulkan", nullptr, nullptr);
8 }


To keep the application running until either an error occurs or the window is closed, we need to add an event loop to the  mainLoop
function as follows:

1 void mainLoop() {
2     while (!glfwWindowShouldClose(window)) {
3         glfwPollEvents();
4     }
5 }


This code should be fairly self-explanatory. It loops and checks for events like pressing the X button until the window has been closed by the user. This is also the loop where we’ll later call a function to render a single frame.

Once the window is closed, we need to clean up resources by destroying it and terminating GLFW itself. This will be our first  cleanup
code:

1 void cleanup() {
2     glfwDestroyWindow(window);
3
4     glfwTerminate();
5 }


When you run the program now you should see a window titled  Vulkan
show up until the application is terminated by closing the window. Now that we have the skeleton for the Vulkan application, let’s
create the first Vulkan object

!

C++ code