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

栏目: 后端 · 发布时间: 5年前

内容简介:[译]Vulkan教程(04)基础代码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:在之前的章节你已经创建了一个Vulkan项目,配置好了项目属性,用示例代码进行了

[译]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:

在之前的章节你已经创建了一个Vulkan项目,配置好了项目属性,用示例代码进行了测试。本章我们将从零开始写代码,先从下面的代码开始:

 1 #include <vulkan/vulkan.h>
 2  
 3 #include <iostream>
 4 #include <stdexcept>
 5 #include <functional>
 6 #include <cstdlib>
 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.

首先,我们include了Vulkan头文件,它来自LunarG SDK,他提供函数、结构体和枚举。 stdexceptiostream 头文件用于报告和传播错误。 functional 头文件用于资源管理小节中要介绍到的lambda函数。 cstdlib 头文件提供了 EXIT_SUCCESSEXIT_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.

这个程序封装了一个class,我们将Vulkan对象保存为private成员,添加了初始化它们的函数,在 initVulkan 函数中调用这些初始化函数。一旦一切就绪,我们就进入主循环,开始渲染帧。我们将在 mainLoop 函数中循环,直到窗口关闭为止。一旦窗口关闭, mainLoop 返回时,我们将确保在 cleanup 函数中销毁使用过的资源。

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,那么我们将抛出一个 std::runtime_error 异常和描述性消息,它会被传回 main 函数,打印到控制台。为了处理各种标准异常类型,我们捕捉更泛型的 std::exception 。我们很快就要处理的一个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 .

粗略地说,本章之后的每篇教程都会添加被 initVulkan 函数调用的新函数,以及添加1个或多个Vulkan对象(作为private成员),这些成员最后都要在 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  <memory> 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.

正如每块用 malloc 申请的内存都需要用 free 释放,当我们不需要它们的时候,我们创建的每个Vulkan对象都需要显式地被销毁。在现代C++代码中,可以用 <memory> 头文件实现自动化的资源管理,但在本教程中我选择了显式地申请和销毁Vulkan对象。毕竟,Vulkan的利基是,无论什么操作都是显式的,以避免错误。所以显式地处理对象的生命周期,对于学习这个API的工作方式是有益的。

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.

学习完本教程后,你可以实现自动资源管理(例如通过 std::shared_ptr )。对于大型的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 函数销毁它。不同对象的这些函数的参数区别很大,但是它们都有一个共同的参数: pAllocator 。这是一个可选参数,它允许你标识一个回调函数,用于以自定义的方式分配内存。本教程中我们将忽略这个参数,总是传给它 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 <vulkan/vulkan.h> line with

如果你想用Vulkan搞离屏渲染,那么不用创建窗口,Vulkan也可以工作得很好。但是显示点东西才刚令人兴奋!首先用下述代码替换 #include <vulkan/vulkan.h>

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

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.

这样,GLFW将包含它自己的定义,且自动加载Vulkan头文件。添加 initWindow 函数,在 run 函数调用其他函数前,先调用它。我们将用这个函数初始化GLFW,并创建窗口。

 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 函数中第一个函数调用应该是 glfwInit() ,它初始化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:

现在剩下的就是创建实际的窗口了。添加private成员 GLFWwindow* window; ,以保存对窗口的引用。用下述代码初始化窗口:

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.

前3个参数标明窗口的宽度、高度和标题。第4个参数允许你可选地标明在哪个显示器上打开窗口,最后一个参数只与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:

用常量代替硬编码的宽度和高度数值是个好主意,因为我们将多次引用这些数据。我在类定义之前添加了下述2行:

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:

现在你应该有个长这样的 initWindow 函数:

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:

为了让app持续运行,直到发生错误或窗口关闭,我们需要在 mainLoop 函数中添加一个事件循环,如下代码所示:

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.

这个代码是不言自明的。它循环检查事件(例如点击X按钮),直到窗口被用户关闭为止。在这个循环里,我们稍后会调用另一个函数来渲染一帧。

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:

一旦窗口被关闭,我们需要销毁资源,关闭GLFW。下面是我们最初的 cleanup 代码:

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 !

运行此程序,现在你可以看到一个标题为 Vulkan 的窗口显示出来,直到你通过关闭按钮终结它。既然我们有了Vulkan程序的骨架,我们来创建第一个Vulkan对象吧!

C++ code 完整C++代码


以上所述就是小编给大家介绍的《[译]Vulkan教程(04)基础代码》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

The Mechanics of Web Handling

The Mechanics of Web Handling

David R. Roisum

This unique book covers many aspects of web handling for manufacturing, converting, and printing. The book is applicable to any web including paper, film, foil, nonwovens, and textiles. The Mech......一起来看看 《The Mechanics of Web Handling》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具